On this page
GET /api/kyc/status/:verificationIdReturns 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
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:
waitingOn | The decision is held on |
|---|---|
null | Nothing. 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
{
"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"
}
workflowVersionis 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
approvedstatus 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.
approvedwithcheckStatus: "failed"is not a contradiction. It means a person reviewed the verification and accepted it despite what the checks found, andreason/reasonCodebelow say what they accepted it despite. Branch onstatus; storecheckStatusalongside 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.
{
"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.
{
"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
| Status | Body | Cause |
|---|---|---|
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.