Errors

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"
  }
}
FieldDescription
typeMachine-readable error category for programmatic handling
messageHuman-readable description for developers (do not show to end users)

HTTP Status Codes

CodeMeaningAction
200Success (all operations)Process the response
400Bad RequestFix your request parameters
401UnauthorizedCheck your API key
403ForbiddenCheck account authorization, balance, or query quota
404Not FoundResource doesn't exist or has been deleted
409ConflictResolve the conflict (duplicate, locked, etc.)
429Too Many RequestsRespect Retry-After header and slow down
500Internal Server ErrorRetry with backoff; contact support if persistent
503Service UnavailableTemporary failure (e.g. profile ensure); safe to retry with backoff

Error Types

The table below lists common error types to illustrate the response format. It is not exhaustive — each endpoint may return additional, operation-specific error types. Refer to the individual endpoint reference for the complete list of errors that endpoint can return.

TypeHTTPDescription
invalid_request_error400Parameter validation or malformed request
invalid_json400Request body is not valid JSON
authentication_error401API key invalid or missing
permission_error403Account is not authorized for this service
insufficient_balance_error403Account balance is insufficient
over_query_limit_error403Query limit exceeded or service validity period expired
profile_not_found404Profile does not exist
case_not_found404AML case does not exist or does not belong to your account
alert_not_found404AML alert does not exist or does not belong to your account
match_not_found404AML match does not exist or does not belong to your account
profile_already_exists409Duplicate externalUserId
profile_deleted409Profile has been deleted
profile_unavailable409Profile state does not support this operation
profile_locked409Profile locked by another process
rate_limit_error429Rate limit exceeded
api_error500 / 503Unexpected server error (500); temporary ensure / infrastructure failure (503). Distinguish by HTTP status.
service_unavailable503Used by some Application paths for lock / infrastructure fail-closed (service temporarily unavailable, please retry later)

Handling Strategies

Client Errors (4xx)

These indicate a problem with your request. Do not retry without fixing the issue.

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
        pass

Server Errors (5xx)

These indicate a server-side issue. Retry with exponential backoff.

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)

Respect the Retry-After header:

if response.status_code == 429:
    retry_after = int(response.headers.get("Retry-After", 60))
    time.sleep(retry_after)

Request ID

Every response includes an X-Request-Id header. Include this when contacting support for faster debugging:

X-Request-Id: req_abc123def456