Skip to main content

Error Codes

All API errors return a consistent JSON structure with an error code, message, and request ID.

Error Response Format

{
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"request_id": "req_abc123",
"details": [
{
"field": "name",
"message": "required field"
}
]
}

General Errors

CodeHTTP StatusDescriptionRecovery
BAD_REQUEST400Invalid request parametersCheck request body and headers
VALIDATION_ERROR400Field validation failedSee details array for specific field errors
UNAUTHORIZED401Missing or invalid API keyCheck your Authorization header
FORBIDDEN403Insufficient permissionsVerify API key scopes and tenant access
NOT_FOUND404Resource not foundCheck the resource ID in your URL
CONFLICT409Resource conflictResource already exists or is in conflicting state
RATE_LIMITED429Rate limit exceededBack off and retry; check X-RateLimit-Reset header
INTERNAL_ERROR500Unexpected server errorRetry with exponential backoff; contact support if persistent
SERVICE_UNAVAILABLE503Service temporarily unavailableRetry after a short delay

Screening Errors

CodeHTTP StatusDescriptionRecovery
SCREENING_FAILED500Screening process failedRetry the screening; switch to ASYNC mode for complex subjects
SCREENING_TIMEOUT503Screening exceeded 30-second timeoutUse ASYNC mode instead of SYNC
INVALID_SUBJECT400Subject data is invalidCheck required fields: type, name

Case Errors

CodeHTTP StatusDescriptionRecovery
CASE_NOT_FOUND404Case does not existVerify the case ID
CASE_ALREADY_CLOSED409Cannot modify a closed caseReopen the case first if changes are needed
INVALID_DISPOSITION400Invalid disposition valueUse: TRUE_POSITIVE, FALSE_POSITIVE, ESCALATED, or NO_ACTION_REQUIRED

Dataset Errors

CodeHTTP StatusDescriptionRecovery
DATASET_NOT_FOUND404Watchlist dataset not foundCheck the dataset source code

Identity Verification Errors

CodeHTTP StatusDescriptionRecovery
VERIFICATION_FAILED500Identity verification process failedRetry the verification
DOCUMENT_INVALID400Document failed validationEnsure document image is clear and the type is supported
FACE_MATCH_FAILED500Face comparison failedRetry with a clearer selfie image
LIVENESS_FAILED500Liveness check failedRetry the liveness check

Handling Errors

Rate Limit (429)

async function screenWithRetry(payload, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(`${BASE_URL}/screenings`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"X-Tenant-ID": TENANT_ID,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});

if (response.status === 429) {
const resetTime = response.headers.get("X-RateLimit-Reset");
const waitMs = new Date(resetTime) - Date.now();
await new Promise((resolve) => setTimeout(resolve, Math.max(waitMs, 1000)));
continue;
}

return response.json();
}
throw new Error("Rate limit exceeded after retries");
}

Validation Error (400)

const response = await fetch(`${BASE_URL}/screenings`, { ... });

if (response.status === 400) {
const error = await response.json();
if (error.code === "VALIDATION_ERROR") {
for (const detail of error.details) {
console.error(`Field '${detail.field}': ${detail.message}`);
}
}
}

Timeout → Switch to Async

If a sync screening times out, retry with async mode:

const response = await fetch(`${BASE_URL}/screenings`, {
method: "POST",
headers: { ... },
body: JSON.stringify({ mode: "SYNC", ... }),
});

if (response.status === 503) {
const error = await response.json();
if (error.code === "SCREENING_TIMEOUT") {
// Retry with async mode
const asyncResponse = await fetch(`${BASE_URL}/screenings`, {
method: "POST",
headers: { ... },
body: JSON.stringify({
mode: "ASYNC",
callback_url: "https://your-server.com/webhooks",
...originalPayload,
}),
});
}
}