Errors
The API uses conventional HTTP status codes and returns a JSON body with an error field (and sometimes a message) on failure.
json
{ "error": "business_not_approved", "message": "Your business must be approved …" }Status codes
| Status | Meaning | Typical causes |
|---|---|---|
200 | OK | Successful GET/upload. |
202 | Accepted | Verification queued (see create verification). |
400 | Bad request | Invalid body, bad/missing field, unsupported file type, file too large. |
401 | Unauthorized | Missing Authorization header, or invalid/revoked API key. |
403 | Forbidden | Production key without an approved business, a publishable key on a secret-only endpoint (secret_key_required), or a requestId owned by another org. |
404 | Not found | Verification ID does not exist (or isn't yours). |
429 | Too many requests | Rate limit exceeded. |
500 | Server error | E.g. pricing not configured for the requested country/ID type. |
Common error bodies
error | Status | Meaning |
|---|---|---|
Missing or invalid Authorization header | 401 | No Bearer token sent. |
Invalid API key | 401 | Key is unknown or revoked. |
Invalid request body | 400 | Verify payload failed validation; see message for details. |
Forbidden | 403 | The requestId belongs to a different organization. |
business_not_approved | 403 | Production access requires an approved business. |
secret_key_required | 403 | A publishable (pk_) key was used on a secret-only endpoint (full result or media). Use a secret (sk_) key from your backend — see authentication. |
Verification not found | 404 | Unknown verification ID. |
File too large (max 25MB) | 400 | Upload exceeded the size cap. |
Too many requests, please try again later. | 429 | Slow down; see rate limits. |
pricing_not_configured | 500 | No price set for that country/ID type — contact Myaza. |
Asynchronous failures
A 202 Accepted from create verification only means the request was queued. The verification can still finish as failed, not_found, or error. Those are not HTTP errors — read them from GET /status/:id or the verification.* webhooks.
Each non-success outcome carries a human-readable reason plus a stable reasonCode you can branch on (e.g. document_expired, selfie_mismatch, identity_not_found). The full catalog is in failure reason codes.
Health check
code
GET /api/kyc/healthA public, unauthenticated endpoint for uptime monitoring.
json
{ "status": "ok" }Handling errors well
- Treat
5xxand429as retryable — back off and retry with the samemetadata.requestIdso you don't create duplicates. - Treat
4xx(except429) as non-retryable — fix the request; retrying unchanged will fail again. - Always read the
error/messagefields; don't rely on status code alone.