Error codes
A failed request answers { success: false, error: { code, message, request_id } } with one of the codes below, and never costs a credit. The request_id is also sent as the X-Request-Id header; quote it when writing to support.
| code | http | when |
|---|---|---|
| UNAUTHENTICATED | 401 | The Authorization header is missing, malformed, or carries a key that does not exist or was revoked. |
| VALIDATION_FAILED | 422 | One or more fields are missing, malformed, or over a limit. error.errors lists each field with its messages. |
| RATE_LIMITED | 429 | The API allows 5 requests per second per key; each browser endpoint allows 20 lookups a minute per visitor, and the published sandbox key allows 30 a minute per address. |
| NOT_FOUND | 404 | The bulk job, monitor or suppression entry named in the path does not exist, or belongs to another account. Nothing is charged. |
| INSUFFICIENT_CREDITS | 402 | The account has no credits left, so the lookup did not run. Free credits renew at the start of each month; packs can be bought from the Billing page. |
| RESULTS_NOT_READY | 409 | Results were requested for a bulk job that is still queued or running. |
| JOB_ALREADY_FINISHED | 409 | A cancel was requested for a bulk job that already reached a terminal status: completed, cancelled, or failed. |
| JOB_CANCELLED | 409 | Results were requested for a job that was cancelled before any address was processed, so there is no results file. |
| JOB_FAILED | 409 | Results were requested for a job that failed before a single row was written, so there is no results file. |
| JOB_NOT_RESUMABLE | 409 | A resume was asked for a run that did not stop because the credit balance ran out, that has not settled yet, or that is already going again. |
| JOB_INPUT_EXPIRED | 409 | A resume was asked for a run whose uploaded list has passed out of the retention window, so there is nothing left to re-run. |
| IP_LIST_LIMIT_REACHED | 409 | A new allow or deny list was asked for when the account already holds the maximum number of lists. |
| JOB_NOT_FINISHED | 409 | A redelivery of the completion webhook was asked for a run that is still queued or running. |
| WEBHOOK_NOT_CONFIGURED | 409 | A redelivery of the completion webhook was asked for a run created without a `webhook_url`, so there is no address to post to and no secret to sign with. |
| INVALID_PUBLISHABLE_KEY | 401 | The pk_ key sent to the browser endpoint is unknown. |
| ORIGIN_NOT_ALLOWED | 403 | The Origin header of the browser request does not match any domain the publishable key allows, or the header is missing. |
| KEY_IP_NOT_ALLOWED | 403 | The secret key was created with an allowlist of source addresses or CIDR ranges, and this request came from elsewhere. |
| KEY_ACCOUNT_MISMATCH | 403 | A secret key belongs to the account it was created on. The person who holds this one is no longer a member of that account, so the key no longer authorises anything. |
| KEY_SCOPE_DENIED | 403 | The secret key was created with a limited set of scopes (email, ip, phone, address, entity, consistency, account), and the endpoint belongs to a family it does not cover. |
| KEY_SPEND_CAP_REACHED | 429 | The key, publishable or secret, was created with a daily credit cap and has reached it today. The counter resets each day. |
| SANDBOX_ENDPOINT_NOT_ALLOWED | 403 | The request carried the published sandbox key, which answers a handful of read-only lookups and nothing else. |
| SANDBOX_VALUE_NOT_ALLOWED | 403 | The endpoint is one the sandbox answers, but only for the sample values the documentation prints, and the request asked about something else. |
| SANDBOX_UNAVAILABLE | 503 | The request carried the published sandbox key on a deployment where the sandbox is turned off. |
| TURNSTILE_FAILED | 403 | The key was created with a Turnstile site key and secret, and the lookup carried no token or one Cloudflare did not confirm. |
| UNKNOWN_FEEDBACK_PROVIDER | 404 | The URL POST /api/v1/email/feedback/{provider}/{key} accepts postmark, ses, mailgun and sendgrid only. |
| INVALID_FEEDBACK_KEY | 401 | The fb_ key in a bounce webhook URL does not exist or was rotated. |
| EMAIL_NOT_VERIFIED | 403 | The key is valid, but its account has not opened the verification link yet, so the API and the MCP server refuse to spend for it. |
| IDEMPOTENCY_KEY_REUSED | 409 | POST /api/v1/email/bulk saw an Idempotency-Key it already knows, but the addresses or webhook URL differ from the request that first used it. |
| ADDRESS_LIST_UNAVAILABLE | 501 | GET /api/v1/address/postcode/{postcode} answers from a licensed address-list partner or from an open register's street listing, and neither covers the country asked about, or the installed listing cannot speak for that postcode. Nothing is charged. |
| ADDRESS_STREETS_NOT_FOUND | 404 | GET /api/v1/address/streets found nothing to report: no address register Spaw syncs carries a street listing for the country, the registers list no street at that postcode, or the listing does not cover it. Nothing is charged. |
| ASN_NOT_FOUND | 404 | GET /api/v1/ip/asn/{asn} found nothing to report: the ASN database assigns no prefix to that number. Nothing is charged. |
| ASN_INDEX_UNAVAILABLE | 501 | GET /api/v1/ip/asn/{asn} needs the index `lookup:index-asns` builds from the ASN database, and it is not installed. Nothing is charged. |
| PHONE_BLOCK_NOT_FOUND | 404 | GET /api/v1/phone/block/{country}/{prefix} found nothing to report: either no numbering plan Spaw syncs covers the country, or no block in it starts with the prefix. Nothing is charged. |
| METHOD_NOT_ALLOWED | 405 | The path exists but not for this verb — a GET where the endpoint takes POST, most often. The response carries an Allow header naming the methods it does take. Nothing is charged. |
| SERVER_ERROR | 500 | Something went wrong on this side. The failure is logged against the request_id in the response, which is the fastest way for support to find it. |
Validation failures carry an extra error.errors object keyed by field. Rate-limit answers carry a Retry-After header. Each code has a Markdown twin at its URL with a .md suffix.