All errors follow a consistent structure. Use HTTP status codes for broad categorization and the error body for specific handling.
Error Response Format
{
"error": {
"type": "invalid_request_error",
"message": "Parameter 'externalUserId' is required"
},
"requestId": "req-example"
}| Field | Description |
|---|---|
type | Machine-readable error category for programmatic handling |
message | Human-readable description for developers (do not show to end users) |
requestId | Optional top-level request identifier for troubleshooting, when available |
HTTP Status Codes
| Code | Meaning | Action |
|---|---|---|
| 200 | Success (all operations) | Process the response |
| 400 | Bad Request | Fix your request parameters |
| 401 | Unauthorized | Check your Bearer access token |
| 402 | Payment Required | Resolve the account balance or test quota issue |
| 403 | Forbidden | Check service access; use error.type to identify product balance or quota failures |
| 404 | Not Found | Resource doesn't exist or has been deleted |
| 409 | Conflict | Resolve the conflict (duplicate, locked, etc.) |
| 429 | Too Many Requests | Slow down; honor Retry-After when provided |
| 500 | Internal Server Error | Follow endpoint-specific recovery rules; retry with backoff only when safe |
| 502 | Bad Gateway | Gateway could not complete the upstream request; follow endpoint-specific recovery rules |
| 503 | Service Unavailable | Temporary failure; confirm whether the operation can be safely retried |
| 504 | Gateway Timeout | Gateway timed out waiting for the upstream; reconcile write outcomes before retrying |
Error Types
The table below lists common error types. It is not exhaustive: use the individual
endpoint reference for operation-specific errors and recovery rules. Gateway authentication,
request-size, routing, and infrastructure failures can occur before the operation is processed.
| Type | HTTP | Description |
|---|---|---|
invalid_request_error | 400 | Parameter validation or malformed request |
invalid_json | 400 | Request body is not valid JSON |
authentication_error | 401 | Bearer access token invalid, expired, or missing |
insufficient_balance | 402 | Calling account failed the shared balance check |
test_quota_exceeded | 402 | Calling account failed the shared test quota check |
permission_error | 403 | Account is not authorized for this service |
insufficient_balance_error | 403 | Product-specific balance check failed; used by Reusable KYC preview and reuse |
over_query_limit_error | 403 | Product-specific quota check failed; used by Reusable KYC preview and reuse |
profile_not_found | 404 | Profile does not exist |
case_not_found | 404 | AML case does not exist or does not belong to your account |
alert_not_found | 404 | AML alert does not exist or does not belong to your account |
match_not_found | 404 | AML match does not exist or does not belong to your account |
profile_already_exists | 409 | Duplicate externalUserId |
profile_deleted | 409 | Profile has been deleted |
profile_unavailable | 409 | Profile state does not support this operation |
profile_locked | 409 | Profile locked by another process |
rate_limit_error | 429 | Rate limit exceeded; other rate-limit types may also be returned |
internal_error | 500 | Unexpected service failure; used by Reusable KYC |
api_error | 500 / 502 / 503 / 504 | Server or gateway failure. Distinguish by HTTP status and follow the endpoint's recovery rules. |
service_unavailable | 503 | Used by some Application paths for lock / infrastructure fail-closed (service temporarily unavailable, please retry later) |
Account and product access checks (402 / 403)
Individual, AML, and Client Access Links check the calling account's service access,
balance, and test quota before processing the operation. Balance and test quota failures
at this shared check return 402 insufficient_balance or 402 test_quota_exceeded.
These checks also apply to read-only queries, share-token creation, and Reusable KYC preview;
a 402 response does not mean that the requested operation incurred a charge.
Reusable KYC preview and reuse additionally check the recipient's Reusable KYC product access.
That check returns 403 reusable_kyc_disabled when the product is not enabled, or
403 insufficient_balance_error / 403 over_query_limit_error for product balance or quota failures.
These 403 types remain part of the current API. Handle the returned HTTP status and error.type
as documented; do not substitute a 402 type for a product-specific 403 type.
Handling Strategies
Client Errors (4xx)
For validation, authentication, and access failures, resolve the condition before retrying.
Rate limits (429) and some conflicts (409) need the handling documented for that condition.
if response.status_code == 400:
error = response.json()["error"]
log.warning(f"Bad request: {error['message']}")
# Fix the request parameters
elif response.status_code == 409:
error = response.json()["error"]
if error["type"] == "profile_already_exists":
# Handle duplicate: fetch existing profile instead
passServer Errors (5xx)
These indicate a server-side issue, but do not establish whether a write took effect.
Follow the endpoint's recovery rules before retrying. In particular, a Reusable KYC reuse
request may have changed the recipient Profile even if its response was lost or failed;
see Reusable KYC: failures and retries.
Do not apply a blanket retry policy to write requests.
The following backoff example is for an operation already known to be safe to retry,
such as a read-only query:
import time
max_retries = 3
for attempt in range(max_retries):
response = make_request()
if response.status_code < 500:
break
time.sleep(2 ** attempt)Rate Limiting (429)
Handle rate limits by HTTP status 429. A response can use rate_limit_error or another
rate-limit type; do not require one specific error.type to recognize this condition.
The diagnostic message is not a retry timer.
Honor Retry-After when it is provided; its value can be a delay in seconds or an HTTP date.
The header is optional. If it is absent or unusable, use bounded exponential backoff with
jitter and reduce request concurrency. There is no universal 60-second retry delay.
Before retrying a write, follow the endpoint's recovery rules. Waiting after a 429 does
not make repeated writes idempotent or resolve an earlier unknown outcome.
Request ID
Every response includes an X-Request-Id header. Include this when contacting support for faster debugging:
X-Request-Id: req_abc123def456