On this page
The API uses conventional HTTP status codes and returns a JSON body with an error field (and sometimes a message) on failure.
{ "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 organisation. |
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. |
environment_mismatch | 403 | The key's environment doesn't match the server it was sent to (e.g. a pk_live_ key against the sandbox host). Use the base URL for the key's environment. |
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 catalogue is in failure reason codes.
Health check
GET /api/kyc/healthA public, unauthenticated endpoint for uptime monitoring.
{ "status": "ok" }Handling errors well
- Retry
429,502,503,504and connection failures with backoff and the same idempotency key. Do not blindly retry every500: preserve its request ID and contact support if it persists. - 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.
Server SDK errors (package preview)
The server SDK is not yet available on the public npm registry. For current integrations, handle the HTTP status and error code as described above. When the package is published, its typed errors will let your backend branch without parsing messages:
import {
AuthenticationError,
IdempotencyConflictError,
InsufficientCreditError,
MyazaError,
RateLimitError,
ValidationError,
} from '@myazahq/trust-sdk';
try {
await myaza.transactions.retrieve('activity_123');
} catch (error) {
if (error instanceof RateLimitError) {
console.log('Retry after seconds:', error.retryAfterSeconds);
} else if (error instanceof ValidationError || error instanceof IdempotencyConflictError) {
console.error(error.code, error.details, error.requestId);
} else if (error instanceof InsufficientCreditError) {
console.log({ pending: error.pending, statusUrl: error.statusUrl });
} else if (error instanceof AuthenticationError) {
console.error('Check the key type and environment.');
} else if (error instanceof MyazaError) {
console.error(error.status, error.code, error.requestId);
}
}Transaction and activity decisions fail closed when credit is unavailable; a
late record is not an authorisation response. A paused customer risk assessment
sets InsufficientCreditError.pending or returns pending_credit, keeps the same
resource and resumes after funding. Do not submit a duplicate.