Create a session
Build with

code
POST /api/kyc/sessions

Mints a hosted verification link for one applicant from one of your published workflows, entirely server to server. You get back a URL that is theirs alone: send it by email, SMS, WhatsApp, or render it as a QR, and the applicant completes the flow on our hosted page with no SDK integration on your side.

The session is the link. It carries one verification, it is traceable to your own reference for the applicant, and once it is submitted it is spent. Forwarding it to a second person does not work. This is the API twin of the dashboard's "Create session" action; the two accept the same request and mint the same thing.

Authentication: Authorization: Bearer sk_… (secret key required). The response contains a live verification credential and the request may carry applicant details, so this endpoint is backend-only. A publishable key receives 403 secret_key_required. Content type: application/json. Production note: sk_live_ keys require an approved business.

Looking for one URL many people can open, each visit starting its own verification? That is a workflow's hosted link. This endpoint is the opposite shape: you know the applicant, and you want a link that is theirs.

Request body
Build with

FieldTypeRequiredDescription
workflowIdstringyesThe published workflow to run, e.g. wf_AbC123dEf456. Drafts and archived workflows are refused.
externalUserIdstringnoYour reference for the subject: your user id on an individual flow, the business on a KYB one. It is what links the resulting verification and entity back to your records, and what a returning applicant resumes by. Strongly recommended.
metadataobjectnoYour own correlation fields for this applicant (a loan id, an account id). Bounded (16 KiB, four levels, 100 keys), stored on the session, inherited by the verification it produces and carried on every webhook about it.
userDataobjectnoWhat you already know about the subject, to prefill the flow: firstName, lastName, dateOfBirth, and for KYB flows businessName. Prefill, never assertion: the applicant confirms or corrects every value, so none of it is treated as verified.
businessobjectnoFor KYB flows, the company where you already know it: country (ISO-2), registrationNumber, registrationName. The applicant lands on a picked-company card instead of a search box, and the register remains the source of truth.
emailstringnoEmail the link to the applicant on your behalf. Optional: deliver it your own way and omit this.
faceReferenceMediaIdstringsee noteBiometric-authentication workflows only: the mediaId of a reference face photo (uploaded via POST /api/kyc/upload with type auth_reference). The applicant's live selfie is matched against this photo instead of a stored enrolment, so you can authenticate somebody you never enrolled through KYC.

A biometric-authentication workflow must name its subject at mint time: pass externalUserId for a user with an active biometric enrolment, or faceReferenceMediaId with a reference photo. Neither present is refused with 422 user_reference_required; a reference without an enrolment with 422 not_enrolled. A biometric-enrolment workflow always requires externalUserId (the template binds a face to a named record). This is checked when the session is created, so a link that could only fail at submit is never minted.

Request
Build with

shell
curl "https://trust.myaza.app/api/kyc/sessions" \
  -H "Authorization: Bearer $MYAZA_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflowId": "wf_AbC123dEf456",
    "externalUserId": "user_42",
    "metadata": { "loanId": "loan_20191" },
    "userData": { "firstName": "John", "lastName": "Doe" },
    "email": "john@example.com"
  }'

Response 201 Created
Build with

json
{
  "session": {
    "sessionId": "cmt1gfjce05g547grqbmjsiqf",
    "url": "https://trust.myaza.co/verify/pXk3...",
    "shortCode": "7K9F-2QHM",
    "expiresAt": "2026-08-21T12:00:00.000Z",
    "kind": "individual",
    "externalUserId": "user_42",
    "metadata": { "loanId": "loan_20191" },
    "workflow": { "id": "wf_AbC123dEf456", "name": "Identity verification", "version": 3 }
  },
  "delivery": { "sent": true }
}
FieldDescription
session.urlThe applicant's link. Treat it like a credential: whoever opens it verifies as this applicant.
session.shortCodeA human-typable code for when a camera cannot scan a QR. Display only, never a credential.
session.expiresAtWhen the link stops accepting a new start: 24 hours for individual flows, 7 days for business (KYB) ones, unless the workflow sets its own session lifetime. A submitted verification is unaffected by expiry.
session.kindindividual or business, following the workflow's subject type.
session.externalUserId, session.metadataYour reference and metadata, echoed exactly as stored. The verification this session produces, and every webhook about it, carry the same values.
deliverynull when no email was given; { "sent": true } or { "sent": false, "reason": "send_failed" } otherwise. A failed send never fails the mint; the link in session.url works regardless.

The config the applicant walks is the workflow's published snapshot, frozen at mint time. Editing or re-publishing the workflow never changes a link that is already in someone's inbox.

Tracking the session
Build with

The sessionId doubles as the verification's id once the applicant submits, so the reference you hold from the start resolves from the start:

  • GET /status/:id reports the attempt live: in_progress with the current step and captured slots, then the full verification lifecycle after submission, and abandoned or expired if the applicant never finishes.
  • Session webhooks (session.started, session.resumed, session.abandoned, session.expired) push the same lifecycle to your backend, and the verification events follow once they submit.
  • Opening the url in a WebView or an iframe? The page tells its host what the applicant is doing, step by step, with nothing to install: see Hosted link events.

Errors
Build with

StatuserrorMeaning
400invalid_inputThe body failed validation; message names the first problem.
403secret_key_requiredA publishable key was used. Call this from your backend with a secret key.
403business_not_approvedsk_live_ before KYB approval. Sandbox keys work from day one.
422workflow_not_availableThe workflow is not published (or is suspended), so it cannot start a verification.
429rate_limitedToo many sessions minted this hour. Retry later, or contact support to raise your limit.