Skip to content

Errors

The single most important thing about this API’s status codes:

An address that fails verification is a successful request. undeliverable arrives as a 200 with a negative status. The 4xx and 5xx responses below mean the request was malformed or the service could not answer.

An integration that treats any non-2xx as “bad address” will reject people during our outages and accept nothing during a rate limit. Treat them as what they are: your bug, your balance, or our problem.

{ "error": "insufficient_credits", "message": "the account has nothing left to spend" }

error is a stable machine-readable string. message is prose and may be reworded; do not branch on it.

Status Meaning What to do
400 Malformed body, missing email, or an unrecognised variant. Fix the request. It will not succeed on retry.
401 Missing or unrecognised credential. See Authentication.
402 insufficient_credits — the account has nothing left to spend. Top up. Deliberately not reported as unknown: what somebody has paid for is not something this service is uncertain about.
403 delegation_not_permitted — the request named an account to charge and this credential may not name one. Remove the header. Ordinary credentials bill their own account.
413 The request body is larger than permitted. Fix the request.
429 Caller or source budget exceeded, or the request pattern looks like directory harvesting. Back off; honour Retry-After. See Limits.
500 The verification engine failed. This says nothing about the address. Retry, then proceed behind a confirmation message.
503 A dependency needed to authorise the request is unavailable. Retry with backoff.
Status Meaning
400 No identifier supplied.
401 Missing or unrecognised credential.
404 No such verification for this credential. An identifier belonging to another caller answers identically to one that never existed.
500 The verification could not be retrieved.
503 Stored results are unavailable.

Proceed behind a confirmation message.

This is worth stating flatly because the tempting alternative — fail the signup — converts our unavailability into your lost customers, silently. The service itself is built on the same rule: when a dependency is down it degrades to unknown and keeps answering rather than failing, and unknown never blocks a registration. Your side of the integration should hold the same line.

A reasonable default:

let result;
try {
result = await verify(email, key);
} catch {
// Unreachable, timed out, 5xx — all the same thing from here.
result = { status: 'unknown', action: 'allow_with_email_confirmation' };
}

Set a client timeout and treat expiry as unknown. The service will answer pending rather than hold a socket open indefinitely, so a long hang is a network problem rather than a slow verification — and a signup form should not wait on one.