Skip to content

Error Codes

On failure, check the HTTP status code first, then the body. Business errors carry a machine-readable code; framework-level failures carry only a message.

Business errors always return a code you can branch on programmatically:

{
"code": "insufficient_balance",
"message": "Insufficient balance for this submission."
}

The code is a contract token — never translate it, never display it, and never branch on the message text, which is prose and may be reworded.

The API returns exactly these 22 codes, with these statuses.

codeHTTPDescription
unauthorized401API key missing, invalid, or inactive.
account_banned403Account suspended. Contact support.
invalid_realtime_request400Malformed realtime request (e.g. a phone number without a + international prefix while country is omitted).
idempotency_key_required400Realtime requests require the Idempotency-Key header.
invalid_idempotency_key422Idempotency-Key must be 1–128 characters from letters, digits and . _ : -
idempotency_conflict409The same Idempotency-Key was used with a different request payload.
request_in_progress409An identical realtime request is still being processed. Retry shortly (Retry-After: 1).
empty_input422The uploaded file contains no usable rows.
product_not_found422The submitted product slug does not exist or is inactive.
product_mode_not_supported422This endpoint does not accept this product mode (realtime products cannot be used on bulk endpoints).
invalid_country422The product does not support the submitted country.
too_few_numbers422The submission is below the product minimum.
too_many_numbers422The submission exceeds the platform maximum.
insufficient_balance402Not enough balance to cover this submission. Top up and retry.
realtime_disabled403Realtime detection is not enabled for this account.
realtime_rate_limited429Realtime rate limit exceeded. Respect retry_after.
product_pricing_unavailable503Pricing for this product is not configured yet. Contact support.
detection_capacity_unavailable503No detection capacity available right now. Retry later.
realtime_route_unavailable503No realtime route available. Retry later.
realtime_fact_cache_unavailable503A realtime dependency is temporarily unavailable. Retry later.
realtime_rate_limiter_unavailable503The rate limiter is temporarily unavailable. Retry later.
internal_error500Unexpected server error. Safe to retry with the same Idempotency-Key.

Not every failure has a code. The task endpoints report four conditions by HTTP status and message alone, because those failures are raised before the business-error path is reached:

HTTPConditionBody
404The task_id does not exist, or belongs to another accountmessage only
404GET /v1/tasks/{token}/download — the result file is unavailable, expired, or no longer in a downloadable statemessage only
422GET /v1/tasks/{token}/result — the result is not ready: the task is not complete, the file has not been generated, or it has expiredmessage only
422Request parameters failed validation{ "message": …, "errors": { … } }

Branch on the HTTP status for these. The message is for your logs and for a human reading an incident, not for control flow.

The right response to a failure depends on whether repeating the request could produce a different answer.

GroupCodesWhat to do
Action required first — an unchanged retry repeats the same failureunauthorized, account_banned, invalid_realtime_request, idempotency_key_required, invalid_idempotency_key, idempotency_conflict, empty_input, product_not_found, product_mode_not_supported, invalid_country, too_few_numbers, too_many_numbers, insufficient_balance, realtime_disabled, product_pricing_unavailableFix the request, the key, or the balance, then send a new one. Retrying is wasted traffic.
Wait, then retry — transient, and the same request should succeed laterrealtime_rate_limited, request_in_progress, detection_capacity_unavailable, realtime_route_unavailable, realtime_fact_cache_unavailable, realtime_rate_limiter_unavailableHonour Retry-After when present, then back off exponentially. The request itself is fine.
Outcome uncertain — the request may or may not have appliedinternal_errorRetry the same body with the same Idempotency-Key.

internal_error is the one case where you cannot tell from the response whether the work happened. Retry it with the same Idempotency-Key: a replay returns the stored result and never charges twice. Generating a fresh key is what turns one charge into two.

The two codeless task failures map onto these groups by status: a 404 on a task endpoint means the token is wrong, and the fix is the same as “action required”; a 422 on the result endpoint is the “wait, then retry” case — it means poll again, not fix something. The polling loop on Task status handles it by reading status rather than by catching an error.

See Rate limits for the full response-header set on a 429.