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

StatusMeaningTypical causes
200OKSuccessful GET/upload.
202AcceptedVerification queued (see create verification).
400Bad requestInvalid body, bad/missing field, unsupported file type, file too large.
401UnauthorizedMissing Authorization header, or invalid/revoked API key.
403ForbiddenProduction key without an approved business, a publishable key on a secret-only endpoint (secret_key_required), or a requestId owned by another org.
404Not foundVerification ID does not exist (or isn't yours).
429Too many requestsRate limit exceeded.
500Server errorE.g. pricing not configured for the requested country/ID type.

Common error bodies

errorStatusMeaning
Missing or invalid Authorization header401No Bearer token sent.
Invalid API key401Key is unknown or revoked.
Invalid request body400Verify payload failed validation; see message for details.
Forbidden403The requestId belongs to a different organisation.
business_not_approved403Production access requires an approved business.
secret_key_required403A 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_mismatch403The 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 found404Unknown verification ID.
File too large (max 25MB)400Upload exceeded the size cap.
Too many requests, please try again later.429Slow down; see rate limits.
pricing_not_configured500No 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

code
GET /api/kyc/health

A public, unauthenticated endpoint for uptime monitoring.

json
{ "status": "ok" }

Handling errors well

  • Retry 429, 502, 503, 504 and connection failures with backoff and the same idempotency key. Do not blindly retry every 500: preserve its request ID and contact support if it persists.
  • Treat 4xx (except 429) as non-retryable: fix the request; retrying unchanged will fail again.
  • Always read the error/message fields; don't rely on status code alone.

Trust SDK errors

@myazahq/trust-sdk exposes typed errors so your backend can branch without parsing messages:

js
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.