code
GET /api/kyc/verifications/:id

Returns the full result of a verification, including the extracted biodata, ID number, and facial-match score. This is the backend counterpart to the minimal status endpoint.

Authentication: Authorization: Bearer sk_…, a secret key only. Calling this with a publishable (pk_) key returns 403 secret_key_required. The verification is scoped to the key's organisation and environment (a sandbox secret key cannot read a production verification).

Never call this from client code. Identity data must only be fetched from your backend with a secret key.

Request

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

Responses

Every response includes verificationId, status, country, idType, createdAt, and workflow, which workflow was responsible for the submission.

approved

json
{
  "verificationId": "ver_01j9...",
  "status": "approved",
  "checkStatus": "verified",
  "externalUserId": "user_42",
  "metadata": { "loanId": "loan_20191" },
  "country": "NG",
  "idType": "bvn",
  "createdAt": "2026-04-27T12:00:00.000Z",
  "completedAt": "2026-04-27T12:00:05.000Z",
  "workflow": {
    "id": "wf_AbC123dEf456",
    "name": "Standard KYC",
    "version": 3
  },
  "result": {
    "idNumber": "12345678901",
    "idNumberMasked": "1234•••901",
    "firstName": "JOHN",
    "lastName": "DOE",
    "middleName": "A",
    "dateOfBirth": "1990-01-01",
    "gender": "Male",
    "dataMatch": true,
    "facialMatch": { "match": true, "confidence": 85 },
    "facialMatchSource": "gov_record"
  }
}

facialMatch is null when no liveness/selfie check was part of the flow. facialMatchSource says which photo the selfie was compared with: gov_record, chip, or document when the workflow allows the photo printed on the document and no stronger photo existed.

workflow is null when the SDK was configured with plain props instead of a workflow. Its version is the published version that actually ran: publishing overwrites a workflow's live configuration in place, so id alone stops describing what happened after your next publish. Inspect the exact configuration a version used under Workflows → Version history.

failed / error / not_found

Carries the human-readable reason and stable reasonCode (same values as the status endpoint and webhooks).

json
{
  "verificationId": "ver_01j9...",
  "status": "declined",
  "checkStatus": "failed",
  "externalUserId": "user_42",
  "metadata": { "loanId": "loan_20191" },
  "country": "NG",
  "idType": "bvn",
  "createdAt": "2026-04-27T12:00:00.000Z",
  "completedAt": "2026-04-27T12:00:05.000Z",
  "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"
}

After a decision

When the verification has been decided, by a reviewer in your dashboard, by your backend through POST /verifications/:id/review or by your workflow, review holds the current decision a person made and statusHistory lists every change, newest first:

json
{
  "verificationId": "ver_01j9...",
  "status": "declined",
  "checkStatus": "verified",
  "review": {
    "decision": "DECLINED",
    "reviewedAt": "2026-04-28T09:14:00.000Z",
    "reviewedById": "api_key:ak_01j9..."
  },
  "statusHistory": [
    {
      "status": "declined",
      "previousStatus": "in_review",
      "source": "api",
      "changedBy": { "type": "api_key", "id": "ak_01j9..." },
      "changedAt": "2026-04-28T09:14:00.000Z",
      "decision": "DECLINED",
      "outcome": null,
      "runId": null,
      "resubmitSteps": []
    },
    {
      "status": "in_review",
      "previousStatus": "processing",
      "source": "workflow",
      "changedBy": { "type": "workflow", "id": "wf_AbC123dEf456" },
      "changedAt": "2026-04-27T12:00:07.000Z",
      "decision": null,
      "outcome": "review",
      "runId": "wfr_01j9...",
      "resubmitSteps": []
    }
  ]
}

Each entry has the same fields as one verification.status_updated webhook, so what you store from the webhook and what you read here agree. The reviewer's internal note is never included.

Attempts

A verification you send back or verify again keeps its id. Once the applicant resubmits, the result describes their latest attempt, attempt counts up, and each earlier attempt is listed under attempts, oldest first:

json
{
  "verificationId": "ver_01j9...",
  "status": "approved",
  "attempt": 2,
  "submittedAt": "2026-04-29T10:02:00.000Z",
  "completedAt": "2026-04-29T10:02:06.000Z",
  "attempts": [
    {
      "attempt": 1,
      "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.",
      "reasonCode": "selfie_mismatch",
      "assuranceLevel": null,
      "decision": "RESUBMISSION",
      "resubmitSteps": ["liveness"],
      "submittedAt": "2026-04-27T12:00:00.000Z",
      "completedAt": "2026-04-27T12:00:05.000Z",
      "resubmittedAt": "2026-04-29T10:02:00.000Z"
    }
  ]
}

An earlier attempt carries what it concluded and why, never its biodata or media. The current result is the one to act on, and statusHistory still lists every decision across all attempts.

Result fields

FieldTypeDescription
externalUserIdstring | nullYour reference for the subject, exactly as supplied: the top-level externalUserId on the submission (or the legacy userId / metadata.userId), or the session it was minted with.
metadataobject | nullYour customer metadata, echoed unchanged.
workflowobject | null{ id, name, version }: the workflow that drove the submission, its current name, and the published version that ran. null for prop-configured SDK mounts.
reviewobject | nullThe current decision a person or your backend made: { decision, reviewedAt, reviewedById }. reviewedById is a user id, or api_key:<id> for a decision made through the API. null when nobody has decided.
statusHistoryarrayEvery change to status, newest first, whoever made it. Empty until something decides the verification. See After a decision.
attemptnumberWhich attempt this result describes. 1 until the verification is sent back and the applicant resubmits.
submittedAtstringWhen this attempt was submitted. completedAt is timed from it.
attemptsarrayThe earlier attempts, oldest first. Empty until the verification is redone. See Attempts.
result.idNumberstring | nullThe plaintext ID number.
result.idNumberMaskedstringThe ID number, masked (e.g. 1234•••901).
result.firstNamestring | nullGiven name from the source record.
result.lastNamestring | nullFamily name from the source record.
result.middleNamestring | nullMiddle name, if available.
result.dateOfBirthstring | nullDate of birth (YYYY-MM-DD).
result.genderstring | nullGender from the source record.
result.dataMatchboolean | nullWhether submitted biodata matched the source record.
result.facialMatchobject | null{ match: boolean, confidence: number }, or null if no facial check ran.
result.facialMatchSourcestring | nullWhich photo the selfie was compared with: gov_record, chip or document (the photo printed on the ID, weaker evidence). null if no facial check ran.
result.facialMatchSkippedstring | nullWhy no facial check ran when one was expected: no_face_on_document when the photo printed on the document was the only photo to compare with and no face could be read on it (your workflow kept the verification for review). null otherwise.

Captured media

The images and videos captured during the flow are fetched per-kind from GET /api/kyc/verifications/:id/media/:kind (selfie, document-front, document-back, liveness-video, document-front-video, document-back-video, and document-portrait, the portrait cut from the document when the selfie was matched to it), also secret key only. These same URLs are delivered in the media object of verification webhooks.

Errors

StatusBodyCause
403{ "error": "secret_key_required" }A publishable (pk_) key was used. Use a secret key.
404{ "error": "Verification not found" }Unknown ID, wrong environment, or another organisation's verification.
401{ "error": "Invalid API key" }Auth failed.