Quickstart
You need: the service base URL and an API key (issued by whoever operates the instance — for the reference deployment, keys live in Railway service variables).
1. Create a verification
Section titled “1. Create a verification”From your backend (never from a browser or mobile app — the API key must not ship to devices):
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_01kyts0zyt4nrgwajvs2nz8w78", "handoff_token": "JdEcex…", "handoff_url": "https://kyc-server-production.up.railway.app/v/JdEcex…", "expires_in_minutes": 30}external_user_refis your user ID — opaque to BAQSHI-KYC, echoed back so you can correlate.handoff_tokenis the only credential the user’s device will ever hold. It is scoped to this one verification, expires in 30 minutes, and can be revoked.
2. Hand off to the user
Section titled “2. Hand off to the user”Pick whichever fits the moment:
| Situation | Do this |
|---|---|
| User is on desktop | Render handoff_url as a QR code — scanning opens the hosted capture page on their phone |
| User is on mobile web | Redirect to handoff_url |
| User is in your Expo app | Pass handoff_token to the Expo SDK |
The hosted page and the SDK drive the same flow: ID photo → randomized pose challenge (look straight, turn left/right) → decision.
3. Receive the decision
Section titled “3. Receive the decision”Your webhook_url receives a signed, PII-free notification:
{ "type": "verification.decided", "verification_id": "ver_…", "status": "approved" }Always verify the signature before trusting it. Then fetch details or an attestation:
# Full status + minimal extracted identity fields (server-to-server only)curl -H "Authorization: Bearer $API_KEY" $BASE/v1/verifications/ver_…
# Signed attestation with only the claims you needcurl -X POST -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \ -d '{"claims": ["verified", "over_18"]}' $BASE/v1/attestations/ver_…What the statuses mean
Section titled “What the statuses mean”| Status | Meaning | Your action |
|---|---|---|
approved | All checks passed | Grant access |
rejected | A check failed decisively (expired doc, failed liveness, face mismatch) | Deny; offer retry or support |
manual_review | Something was uncertain or suspicious | Wait — a reviewer will decide, then the webhook fires again |
Details on every rejection and review reason: Decision states.