Errors

When a request fails, the API answers with an HTTP status and a JSON body that names the problem. No credit is ever used for a request that ends in an error.

The error body

{
  "error": {
    "code": "insufficient_credits",
    "message": "Not enough credits. Buy a pack to continue.",
    "request_id": "req_7Hq2LmX9cV4bN8tR1zK6wD"
  }
}
  • code is stable and machine-readable: branch on it.
  • message is for people and may change: do not parse it.
  • request_id identifies the request (also in the X-Request-Id header). Quote it when you contact support.

429 and 503 answers also carry Retry-After: the number of seconds to wait before trying again.

Every error code

CodeHTTPWhen it happensWhat to doRetry?
invalid_request400A parameter is missing, has the wrong type or is out of range, or the API key was sent in the URL. The message names the fields at fault.Correct the request. Send the key in the Authorization header, never in the query string.No: fix the request
unauthorized401No API key was sent, the key is malformed, or it has been revoked or rolled.Send a current key as Authorization: Bearer <key> (or X-Api-Key). Create a new key in the dashboard if needed.No: fix the request
insufficient_credits402The account has no credits left for this request (or not enough for a bulk job).Buy a credit pack in the dashboard, then retry. Nothing was charged for the failed request.After you fix the account
forbidden403The key lacks the scope this endpoint needs (for example bulk), or the account is suspended or on a billing hold.Use a key with the right scope, or check the notices in your dashboard.After you fix the account
forbidden_origin403The key is restricted to a list of browser origins and the request came from another Origin.Call the API from an allowed origin, or update the allowed origins of the key.No: fix the request
not_found404The resource does not exist or belongs to another account.Check the id. Ids are only visible to the account that created them.No: fix the request
conflict409The request does not fit the current state of the resource, such as starting a bulk job that is already running or downloading results before a job has finished.Read the job again and act on its current status.No: fix the request
length_required411A bulk upload was sent without a Content-Length header (for example as a chunked stream).Send the file with a known length. Most HTTP clients do this when you pass the whole file.No: fix the request
payload_too_large413The request body is over the limit: 100 MB for a bulk upload, 100,000 addresses for a JSON list.Split the list, or upload large files in the dashboard, which takes files up to 1 GB.No: fix the request
rate_limited429The account or key sent more requests per second than its limit allows.Wait for the number of seconds in Retry-After, then retry. Spread requests evenly over time.Yes, after Retry-After
abuse_throttled429Too many recent requests ended without a definite answer (free outcomes) compared with charged ones, so the account is slowed down for a while.Wait for Retry-After. Avoid re-checking the same failing addresses in a tight loop.Yes, after Retry-After
key_daily_cap429This key reached the daily credit cap set for it in the dashboard.Raise or remove the cap for this key in the dashboard, use another key, or wait until the cap resets the next day.Yes, after Retry-After
internal_error500Something failed on our side. No credit was used.Retry later. If it keeps happening, contact support and quote the request_id.Yes, with backoff
service_unavailable503Validation is paused for a short time, for example while a dependency recovers. No credit was used.Wait for Retry-After, then retry. In sign-up forms, accept the address and check it later.Yes, after Retry-After
upstream_capacity503A bulk job could not be admitted right now because validation capacity is limited. No credit was used.Start the job again later; it stays in the ready state until then.Yes, after Retry-After

Retrying safely

  • Retry 429 and 503 after the number of seconds in Retry-After, with a cap on attempts (three is plenty). These answers are never charged, so retrying them cannot double-charge.
  • Back off when there is no Retry-After: wait about half a second, then one, then two, adding some randomness so many clients do not retry at the same moment.
  • Do not retry key_daily_cap or long abuse_throttled waits in a loop: they last until the next day or for an hour.
  • Do not retry 4xx errors other than 429 without changing the request: the same request will fail again.
  • Network failures: a check that timed out on your side may have completed on ours. Retrying a validation is safe but may cost a second credit; reads (GET) can always be retried.

The official SDKs follow these rules for you.

Errors in sign-up forms

On a sign-up form, an error from us should never stop a real person. Treat 402 insufficient_credits, 429 and 503 (and network failures) like an unknown result: accept the address, store it, and check it again later. Only an actual undeliverable result should ask the person to correct their address. See the sign-up form guide.

Results that are not errors

A check that could not reach a definite answer is not an error: it is a normal 200 response with the status unknown (free). Handle it as a result; see the unknown status.

Updated · Maintained by the email-validation.org team