Create a verification
Build with

code
POST /api/kyc/verify

Submits an identity for verification. The request returns immediately with 202 Accepted and a verificationId; the actual verification runs asynchronously. Receive the outcome via webhooks or by polling GET /status/:id.

Authentication: Authorization: Bearer pk_… (required). Content type: application/json. Production note: pk_live_ keys require an approved business.

Request body
Build with

FieldTypeRequiredDescription
countrystringyesISO-3166 alpha-2 country code: a government-database market (NG, GH, KE, ZA, CI) or any country enabled for global document verification.
idTypestringyesID type identifier, e.g. bvn. See Countries & ID types.
idNumberstringno*The ID number. Required for number-based IDs; omit for pure document flows.
userDataobjectnoApplicant-provided details to cross-check: firstName, lastName, dateOfBirth.
mediaIdsobjectnomediaIds from POST /upload. Keys: documentFront, documentBack, selfie, documentFrontVideo, documentBackVideo, livenessVideo.
externalUserIdstringnoYour stable reference for the person being verified (your user id). It is returned as externalUserId, links the resulting entity, and rides every webhook about this verification. Strongly recommended.
metadataobjectyesRequest metadata (see below). Any extra keys are your customer metadata: bounded (16 KiB, four levels, 100 keys), stored apart from Myaza's own fields, and echoed in responses and on every webhook about this verification. Use opaque correlation values (a loan id, an account id), never credentials or unnecessary personal data.
metadata.requestIdstringyesYour unique idempotency key for this request.
metadata.userIdstringnoLegacy location for your user reference. Prefer the top-level externalUserId; when both are present the top-level field wins.
metadata.deviceobjectnoFree-form device metadata; forwarded to the dashboard.

* Whether idNumber and which mediaIds are needed depends on the ID type. Check its features from GET /config.

Optional header

HeaderDescription
X-SDK-VersionThe SDK version making the call; recorded with the verification for support.

Request
Build with

shell
curl "https://trust.myaza.app/api/kyc/verify" \
  -H "Authorization: Bearer $MYAZA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "country": "NG",
    "idType": "drivers-license",
    "idNumber": "ABC12345",
    "userData": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "1990-01-01" },
    "mediaIds": { "documentFront": "media_01j9abc...", "selfie": "media_01j9def..." },
    "externalUserId": "user_42",
    "metadata": { "requestId": "order_1001", "loanId": "loan_20191" }
  }'

Response 202 Accepted
Build with

json
{
  "verificationId": "ver_01j9...",
  "status": "processing",
  "externalUserId": "user_42",
  "metadata": { "loanId": "loan_20191" }
}

externalUserId and metadata come back exactly as stored, so a retry of the same requestId returns the same values.

The verification is now queued. Track it via its verificationId.

processing is the same word Get verification status returns for this id a moment later. There is one status vocabulary across the whole API, so nothing changes meaning between the response that accepts a submission and the one that reports on it.

Idempotency
Build with

metadata.requestId is your idempotency key. If you submit a request with a requestId that already exists for your organisation, the API returns the existing verification instead of creating a new one:

json
{ "verificationId": "ver_01j9...", "status": "approved" }

Always send a stable requestId per logical verification so retries (timeouts, network errors) never create duplicates or double-charge you. Reusing another organisation's requestId is not possible: a collision across orgs returns 403.

Errors
Build with

StatusBodyCause
400{ "error": "Invalid request body", "message": "…" }Validation failed (bad country, missing requestId, etc.).
401{ "error": "Invalid API key" }Auth failed.
403{ "error": "Forbidden" }The requestId belongs to another organisation.
403{ "error": "business_not_approved", … }Production key but business not approved.
429{ "error": "Too many requests, please try again later." }Rate limit exceeded.

An accepted request (202) can still end in a failed, not_found, or error status later, for example insufficient credit, an ID not found in the government database, or a face mismatch. Those outcomes arrive via status/webhook, not as HTTP errors, and each carries a reason plus a stable reasonCode. See the verification lifecycle and the failure reason codes.