Skip to content

Error handling

Every error response is JSON with a single message field describing what went wrong:

{
  "message": "externalUserId is required"
}

The HTTP status code is your primary signal. The body is for logging and the end-user-facing message you choose to surface.


Status codes

Status Category What it means What your client should do
200 OK Success Request completed. Process the response body.
201 Created Success Resource created. Same as 200; the new resource is in the body.
202 Accepted Success Request was accepted for asynchronous processing (e.g. a webhook ingest, a hosted verification session creation). Treat as success; observe the resource via GET or wait for the webhook.
400 Bad Request Client The request is malformed or missing a required field. The body's message describes what's wrong. Fix the request; do not retry the same payload.
401 Unauthorized Client X-Api-Key / X-Api-Secret headers are missing or don't match an active key pair. Verify your credentials. If they were valid yesterday, check the product portal — they may have been deactivated.
403 Forbidden Client Credentials are valid but your product can't access this specific resource (e.g. an applicant that belongs to a different product). Stop and review. Repeating the call won't help.
404 Not Found Client The applicant / level / document referenced in the URL does not exist for your product. Check the externalUserId / id; consider whether you need to create the resource first.
422 Unprocessable Entity Client The request was syntactically valid but semantically rejected — for example, calling /verify on an applicant that has no eligible verification level configured. Fix the data and retry.
429 Too Many Requests Client You've exceeded a per-IP rate limit (in particular, auth endpoints are capped at 20/min). The response includes a Retry-After header with the seconds to wait. Back off until Retry-After elapses, then retry. Implement client-side rate limiting if you see this often.
500 Internal Server Error Server Unexpected server error. Safe to retry idempotent requests after a brief back-off. Persistent? Reach out to support.
502 Bad Gateway / 503 Service Unavailable / 504 Gateway Timeout Server Transient infrastructure error, often during deploys. Retry with exponential back-off (~1 s, 2 s, 4 s, 8 s, capped at ~30 s).

The API does not currently emit 409 Conflict. Creating the same applicant twice via POST /v1/applicants is idempotent on externalUserId — you get 200 OK with the existing applicant, not a conflict.


Idempotency & retries

  • GET, DELETE, and PUT requests are idempotent — safe to retry on any 5xx or network failure.
  • POST /v1/applicants is idempotent on externalUserId — sending the same externalUserId twice returns the existing applicant, not a duplicate.
  • All other POST requests are not automatically idempotent. If you're worried about duplicates from a retry storm, store a client-side hash of (endpoint + payload) and skip the second send.

Validation error example

Sending a creation request without the required externalUserId:

{
  "message": "externalUserId is required"
}

If multiple fields fail, the response describes the first problem encountered — the API stops at the first missing field rather than returning a list. Fix and retry.


What to log

For every non-2xx response, log:

  • The HTTP method + path you called.
  • The full response body.
  • The exact UTC timestamp of the request.
  • For 429s, the Retry-After header value.

Don't log request bodies that contain documents, selfies, or PII. Don't log the X-Api-Secret header.


Talking to support

If a status code is genuinely unexpected (e.g. 500 on a request that worked yesterday), open a ticket with:

  • The full request method + URL (path only — strip query strings that contain personal info).
  • The exact UTC timestamp.
  • The applicant externalUserId if relevant.
  • A 1–2 sentence description of what you expected vs got.

Don't paste API keys or applicant PII into the ticket.