
# Spot checks

```
POST /api/kyc/checks/individual
POST /api/kyc/checks/business
GET  /api/kyc/checks/individual
GET  /api/kyc/checks/business
GET  /api/kyc/checks/individual/:id
GET  /api/kyc/checks/business/:id
```

Run a one-off check without the SDK capture flow: verify a person's ID number against the government database, or a business registration number against the registry. This is the server-to-server counterpart of the dashboard's Spot Checks tabs — the same gates, pricing and sandbox behaviour, and the same history (API checks appear there labelled "API").

**Authentication:** `Authorization: Bearer sk_…` (**secret keys only**, for the whole surface). Results carry PII, so this never belongs in client-side code.
**Production note:** `sk_live_` keys require an [approved business](https://trust.myaza.co/documentation/environments/markdown#production). Sandbox and development checks are free and serve [test data](https://trust.myaza.co/documentation/sandbox-testing/markdown).

Checks run **asynchronously**: the submit returns `202` with a `verificationId` within milliseconds, and the result is ready seconds later on the detail endpoint.

## Individual checks

```
POST /api/kyc/checks/individual
```

| Field | Required | Description |
|---|---|---|
| `country` | yes | `NG`, `GH`, `KE`, `ZA` or `CI` (the government-database markets). |
| `idType` | yes | The ID type, e.g. `bvn`, `nin`, `passport`. See [Countries & ID types](https://trust.myaza.co/documentation/id-types/markdown). |
| `idNumber` | no* | The ID number. Required for number-based IDs; a document ID may instead send the document front for extraction. |
| `userData` | no | Details to validate against the government record: `firstName`, `lastName`, `dateOfBirth`. |
| `mediaIds` | no | Pre-uploaded photos from [`POST /upload`](https://trust.myaza.co/documentation/api-upload/markdown): `documentFront`, `documentBack`, `selfie`. A selfie adds the facial comparison against the record photo. |
| `images` | no | The same three slots **inline** instead of pre-uploaded: each an https URL, a data URI, or base64 — the same forms the [face match](https://trust.myaza.co/documentation/api-face-match/markdown) endpoint takes. Send each slot as `mediaIds` **or** `images`, never both. |
| `consent` | yes | Must be `true`: you attest the person consented to the check. |
| `requestId` | no | Your idempotency key. A retry with the same value returns the same check instead of running (and billing) a second one. Recommended. |

```bash
curl -X POST https://trust.myaza.app/api/kyc/checks/individual \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "country": "NG",
    "idType": "bvn",
    "idNumber": "12345678901",
    "userData": { "firstName": "John", "lastName": "Doe" },
    "consent": true,
    "requestId": "check-user-42-2026-08-20"
  }'
# → 202 { "verificationId": "cmt…", "status": "pending" }
```

Then read the result:

```
GET /api/kyc/checks/individual/:id
```

```json
{
  "check": {
    "id": "cmt…",
    "status": "verified",
    "country": "NG",
    "idType": "bvn",
    "idNumber": "12345678901",
    "result": {
      "firstName": "JOHN",
      "lastName": "DOE",
      "dateOfBirth": "1990-01-01",
      "dataMatch": true,
      "facialMatch": { "match": true, "confidence": 85 }
    },
    "govRecord": { "…": "customer-safe record extract" },
    "media": { "selfie": "https://trust.myaza.app/api/kyc/verifications/…/media/selfie" },
    "chargedAmount": "0.0500",
    "createdAt": "…",
    "completedAt": "…"
  }
}
```

`status` is `pending` until processing finishes, then `verified`, `failed`, `not_found` or `error` with `reason` and a stable [`reasonCode`](https://trust.myaza.co/documentation/errors/markdown). `result` is present on `verified` only.

## Business checks

```
POST /api/kyc/checks/business
```

| Field | Required | Description |
|---|---|---|
| `country` | yes | ISO-2 country code (about 48 registry countries are supported). |
| `registrationNumber` | yes | The registration number (e.g. `RC123456`). |
| `registrationName` | no | The registered name, cross-checked against the registry when given. |
| `subdivisionCode` | maybe | ISO 3166-2 region (e.g. `US-DE`) — **required** for the countries whose registry is split by region (US, IN, CA, AE) and rejected elsewhere. |
| `product` | no | The check product; defaults to the standard business check. Nigeria adds tax-related products. |
| `consent` | yes | Must be `true`. |
| `requestId` | no | Your idempotency key, as above. |
| `sandboxOutcome` | no | `verified` or `not_found` — pins the canned result outside production. Silently ignored on live keys. |

The detail (`GET /api/kyc/checks/business/:id`) returns the registry's answer as `businessRecord`: company particulars, status, share capital and key personnel in a customer-safe extract, plus `businessName`, the `product`, and the region the registry was asked about.

## History

```
GET /api/kyc/checks/individual
GET /api/kyc/checks/business
```

Paginated, newest first, scoped to your organisation and the key's environment. Query parameters: `status` (`pending` / `verified` / `failed` / `not_found` / `error`), `country`, `idType` (individual) or `product` (business), `from` / `to` (ISO dates), `page`, `pageSize` (max 100). Rows are light — identifiers, status, cost, timestamps and `initiatedVia` (`api` or `dashboard`) — with the full result on the detail endpoints.

A check you no longer want in your history can be removed with `DELETE /api/kyc/checks/individual/:id` or `DELETE /api/kyc/checks/business/:id`. See [Delete records](https://trust.myaza.co/documentation/api-manage-records/markdown): the delete is soft, and a check that is still running is refused with `409 check_in_progress`.

## Errors

| Status | Code | Meaning |
|---|---|---|
| 400 | `invalid_input` | The body failed validation, or a slot was sent both as `mediaIds` and `images`. |
| 400 | `product_unsupported` | That product is not offered for the country. |
| 400 | `subdivision_required` / `subdivision_unsupported` / `subdivision_unknown` | The registry-region rule above. |
| 400 | `invalid_image` / `unsupported_media_type` / `image_too_large` / `image_url_not_allowed` / `image_fetch_failed` | An inline image problem — same rules as [face match](https://trust.myaza.co/documentation/api-face-match/markdown). |
| 402 | `insufficient_credits` | Your balance cannot cover the check. |
| 403 | `spot_checks_disabled` / `business_checks_disabled` | The module is not enabled for your organisation. |
| 403 | `id_type_not_enabled` | The ID type is not granted to your organisation, or the required feature is disabled. |
| 403 | `spot_check_unavailable` | The ID type is temporarily switched off for spot checks. |
| 403 | `secret_key_required` | A publishable key was used; this surface is secret-key only. |
| 403 | `business_not_approved` | A live key before KYB approval. |
| 422 | `only_test_ids_allowed` | A sandbox key sent a real ID number; use the published [test IDs](https://trust.myaza.co/documentation/sandbox-testing/markdown). |
| 429 | `rate_limited` | The hourly verification cap was reached; retry later. |
