code
GET /api/kyc/status/:verificationId

Returns the minimal lifecycle state of a verification. status is the merged top-line (not_started, in_progress, processing, in_review, awaiting_resubmission, approved, declined, abandoned, expired, error) and checkStatus is what the checks themselves found (pending, verified, failed, not_found, error). They differ when a person overrode the automated result. See Status and checkStatus.

This endpoint is publishable-safe: it can be called with the pk_ key that ships in your SDK, so it deliberately returns no PII, no match scores, and no result data. To read the full result + extracted biodata, use Get verification result with a secret (sk_) key from your backend.

Webhooks are the recommended way to learn about completion without polling.

Authentication: Authorization: Bearer pk_… or sk_… (required). A verification is only visible to the organisation that created it.

Request

shell
curl "https://trust.myaza.app/api/kyc/status/ver_01j9..." \
  -H "Authorization: Bearer $MYAZA_PUBLISHABLE_KEY"

Responses

Every response includes verificationId, status, createdAt, your externalUserId (so a publishable key can tell which user an id belongs to; your metadata stays on the secret-key result), and the workflow attribution pair workflowId / workflowVersion (both null when the SDK was configured with plain props instead of a workflow), and attempt with its submittedAt. A verification you send back or verify again keeps its id: when the applicant resubmits, attempt counts up and submittedAt and completedAt describe their latest attempt.

Why a verification is still processing

processing means "no answer yet", and it covers both the eight seconds we spend reading a document and the eight days an address presence watch runs. Those read identically on a row, so waitingOn says which:

waitingOnThe decision is held on
nullNothing. The checks are simply still running.
"screening"A sanctions, PEP or adverse-media screen.
"key_people"The directors and owners on a business application finishing their own verifications.
"address_presence"A presence watch confirming the person lives at the address. Days, not seconds.

It is only ever set while a decision run is genuinely parked, and it clears the moment the run continues. Values are add-only: treat one you do not recognise as a check you have not learned about yet, rather than mapping it to a known one.

processing / approved

json
{
  "verificationId": "ver_01j9...",
  "status": "approved",
  "checkStatus": "verified",
  "externalUserId": "user_42",
  "workflowId": "wf_AbC123dEf456",
  "workflowVersion": 3,
  "attempt": 1,
  "createdAt": "2026-04-27T12:00:00.000Z",
  "submittedAt": "2026-04-27T12:00:00.000Z",
  "completedAt": "2026-04-27T12:00:05.000Z"
}

workflowVersion is the published version that actually ran. Publishing a workflow overwrites its live configuration in place, so keep the pair if you need to explain later exactly which rules a submission went through. The workflow's human-readable name is on the full result; this endpoint stays minimal.

An approved status confirms the person was accepted, but carries no identity data. Fetch the full result with a secret key to read the biodata and facial-match score.

approved with checkStatus: "failed" is not a contradiction. It means a person reviewed the verification and accepted it despite what the checks found, and reason/reasonCode below say what they accepted it despite. Branch on status; store checkStatus alongside it.

declined / error

declined means the person was not accepted, either because the checks did not pass or because a reviewer declined them. error means a system problem occurred on our side and you were not charged. Both include a human-readable reason and a stable reasonCode you can branch on. See failure reason codes.

A reason is present whenever the checks did not pass, even on a verification a reviewer later approved.

json
{
  "verificationId": "ver_01j9...",
  "status": "declined",
  "checkStatus": "failed",
  "reason": "The selfie does not match the photo on the government record for this ID. Take it again in good light, looking straight at the camera. If it still does not match, check that the ID number entered is the right one.",
  "reasonCode": "selfie_mismatch",
  "createdAt": "2026-04-27T12:00:00.000Z",
  "completedAt": "2026-04-27T12:00:05.000Z"
}

declined with identity_not_found

An ID number the government database does not hold is a decline like any other; the reasonCode is what tells it apart from a failed face match. There is no separate not_found status.

json
{
  "verificationId": "ver_01j9...",
  "status": "declined",
  "checkStatus": "not_found",
  "reason": "The BVN number was not found in the government database.",
  "reasonCode": "identity_not_found",
  "createdAt": "2026-04-27T12:00:00.000Z",
  "completedAt": "2026-04-27T12:00:05.000Z"
}

Errors

StatusBodyCause
404{ "error": "Verification not found" }Unknown ID, or it belongs to another organisation.
401{ "error": "Invalid API key" }Auth failed.

Polling guidance

If you must poll, do so with backoff (e.g. every 2–3 seconds, widening over time) and stop once status is no longer pending. Prefer webhooks for production. Once complete, fetch the full result from your backend.