Errors
The single most important thing about this API’s status codes:
An address that fails verification is a successful request.
undeliverablearrives as a200with a negativestatus. 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.
POST /v1/verifications
Section titled “POST /v1/verifications”| 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. |
GET /v1/verifications/{id}
Section titled “GET /v1/verifications/{id}”| 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. |
What to do when we cannot answer
Section titled “What to do when we cannot answer”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' };}Timeouts are yours to set
Section titled “Timeouts are yours to set”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.