
# Create a verification

```
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](https://trust.myaza.co/documentation/webhooks/markdown) or by polling [`GET /status/:id`](https://trust.myaza.co/documentation/api-verification-status/markdown).

This call is also what fires [`verification.started`](https://trust.myaza.co/documentation/webhooks/markdown#when-the-applicant-submits). That is the submission event: it fires here, before any check has run, and is how your backend learns that somebody finished the flow.

**Authentication:** `Authorization: Bearer pk_…` (required).
**Content type:** `application/json`.
**Production note:** `pk_live_` keys require an [approved business](https://trust.myaza.co/documentation/environments/markdown#production).

## 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](https://trust.myaza.co/documentation/id-types/markdown). |
| `idType` | string | yes | ID type identifier, e.g. `bvn`. See [Countries & ID types](https://trust.myaza.co/documentation/id-types/markdown). |
| `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 | `mediaId`s from [`POST /upload`](https://trust.myaza.co/documentation/api-upload/markdown). 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](https://trust.myaza.co/documentation/identity-hub/markdown), and rides every [webhook](https://trust.myaza.co/documentation/webhooks/markdown#your-reference-on-every-event) 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`](https://trust.myaza.co/documentation/api-config/markdown).

### Optional header

| Header | Description |
|---|---|
| `X-SDK-Version` | The SDK version making the call; recorded with the verification for support. |

## Request

```bash
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`

```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](https://trust.myaza.co/documentation/api-verification-status/markdown) 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:

```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

| 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](https://trust.myaza.co/documentation/rate-limits/markdown) 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](https://trust.myaza.co/documentation/verifications/markdown) and the [failure reason codes](https://trust.myaza.co/documentation/verifications/markdown#failure-reason-codes).
