Create a verification
POST /api/kyc/verifySubmits 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
| Field | Type | Required | Description |
|---|---|---|---|
country | string | yes | ISO-3166 alpha-2 country code: a government-database market (NG, GH, KE, ZA, CI) or any country enabled for global document verification. |
idType | string | yes | ID type identifier, e.g. bvn. See Countries & ID types. |
idNumber | string | no* | The ID number. Required for number-based IDs; omit for pure document flows. |
userData | object | no | Applicant-provided details to cross-check: firstName, lastName, dateOfBirth. |
mediaIds | object | no | mediaIds from POST /upload. Keys: documentFront, documentBack, selfie, documentFrontVideo, documentBackVideo, livenessVideo. |
externalUserId | string | no | Your 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. |
metadata | object | yes | Request 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.requestId | string | yes | Your unique idempotency key for this request. |
metadata.userId | string | no | Legacy location for your user reference. Prefer the top-level externalUserId; when both are present the top-level field wins. |
metadata.device | object | no | Free-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
| Header | Description |
|---|---|
X-SDK-Version | The SDK version making the call; recorded with the verification for support. |
Request
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
{
"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
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:
{ "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
| Status | Body | Cause |
|---|---|---|
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 afailed,not_found, orerrorstatus 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 areasonplus a stablereasonCode. See the verification lifecycle and the failure reason codes.