Baqshi HQ ยท Identity Infrastructure

BAQSHI-KYC

Self-hosted identity verification, designed around New Zealand's standards โ€” AI document inspection, live face checks, encrypted storage that can go offline, and signed attestations so your products never need to touch raw ID data.

Live service  NZ-first design  API + Expo SDK

๐Ÿ“š Full documentation: kyc-docs-production.up.railway.app โ€” integration guides, security architecture, threat model, fraud-signal catalogue, incident runbooks, NZ compliance mapping, and the API reference.

What this service does

When one of our products needs to know that a user is a real, living person who matches a genuine government ID, it sends them here. The user photographs their ID, completes a short live face challenge (turn your head when asked โ€” a photo or video replay can't follow instructions), and our pipeline decides: approved, rejected, or manual review. The requesting product gets back a signed "yes, verified" attestation โ€” never the ID images themselves.

The verification pipeline, in order

  1. Deterministic checks โ€” ICAO 9303 machine-readable-zone check digits (the maths printed into every passport), expiry rejection.
  2. AI document inspection โ€” Claude vision reads the document fields and actively looks for tampering: photo substitution, font mismatches, disagreement between the MRZ and the printed text.
  3. Biometrics โ€” the selfie is matched against the document portrait (ArcFace embeddings), and liveness is proven with a randomized pose challenge. All face processing runs on our own server โ€” biometric data is never sent to any third party.
  4. Decision โ€” fail-safe by construction: anything uncertain goes to a human reviewer, never to silent auto-approval.

New Zealand standards alignment

Plain-language summary of how the system is designed against the three NZ frameworks that matter for identity verification. This is a design statement, not a certification.

FrameworkWhat it asksHow BAQSHI-KYC answers
AML/CFT Act โ€” Identity Verification Code of Practice Verify name + date of birth from an approved photo ID, and that the person presenting it is its holder. Document authenticity checks (MRZ maths + AI tamper inspection), biometric face match to the document portrait, liveness challenge, and a complete tamper-evident audit trail of every step.
Biometric Processing Privacy Code 2025 Process biometrics only with safeguards: necessity, transparency, retention limits, no repurposing. Biometrics processed locally only, used solely for the match/liveness decision, never used to train anything, deleted with the verification. Users see what is collected at capture time. Retention: 30 days hot, then encrypted offline archive; erasure on request (see below).
Privacy Act 2020 (IPP 5, 9, 13) Reasonable security safeguards, keep no longer than necessary, honour deletion. Per-record envelope encryption (AES-256-GCM), PII kept out of the operational database, hash-chained audit log, and cryptographic erasure: destroying a record's data key makes every copy โ€” including offline archives โ€” permanently unreadable.

Retention, in one paragraph

Verification artifacts (ID photos, selfie frames, extraction data) live encrypted in the cloud vault for 30 days โ€” long enough to resolve disputes and manual reviews. After that they are bundled, hash-manifested, and moved to offline storage. The operational database keeps only the decision, minimal identity fields, and hashes. A deletion request destroys the encryption keys: the data is gone everywhere at once, including on the offline media.

Security architecture

Integrating (for our products, and future API users)

Three calls from your backend, one flow on the user's device.

1 โ€” Create a verification (server-to-server)

curl -X POST $BASE/v1/verifications \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"external_user_ref": "user-123", "webhook_url": "https://yourapp.com/kyc-hook"}'

# โ†’ { "verification_id": "ver_โ€ฆ", "handoff_token": "โ€ฆ", "handoff_url": "https://โ€ฆ/v/โ€ฆ" }

Show handoff_url as a QR code (desktop) or open it / pass the token to the Expo SDK (mobile). The token expires in 30 minutes.

2 โ€” The user completes capture

Via the hosted page at /v/{token} (no app needed), or in your Expo app:

import { BaqshiKyc } from "@baqshi/kyc-expo";

const session = new BaqshiKyc({ baseUrl: BASE }).session(token);
await session.uploadDocument(docPhoto.uri, "front");
await session.runLivenessFlow(async (pose, i, prompt) => {
  showPrompt(prompt);                      // "Turn your head to your left"
  return (await camera.takePictureAsync()).uri;
});
const result = await session.waitForDecision();

3 โ€” Receive the decision

Your webhook receives {type, verification_id, status}. Verify the signature before trusting it:

# signature = HMAC_SHA256(key, f"{timestamp}.{raw_body}")
expected = hmac.new(KEY, f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
assert hmac.compare_digest(expected, request.headers["X-Baqshi-Signature"])
assert abs(time.time() - int(ts)) < 300   # reject stale deliveries

Then fetch details or request an attestation:

GET  /v1/verifications/{id}                 # status + minimal extracted fields
POST /v1/attestations/{id}                  # {"claims": ["verified", "over_18"]}
GET  /v1/attestations/public-key            # PEM for signature verification
DELETE /v1/verifications/{id}/data          # cryptographic erasure (privacy requests)
GET  /v1/review/queue ยท POST /v1/review/{id}  # manual review operations

Full interactive API reference: /docs (OpenAPI).

Operational notes