Rate limits

Headers on every response

Rate limits protect two things: our service, and the reputation of the addresses we probe from. The second one matters to you more than the first, because a verifier that gets its IPs blocked returns unknowns instead of verdicts.

Every response carries your remaining budget in headers, so a well-behaved client never has to guess. Read X-RateLimit-Remaining and slow down before you hit zero rather than after.

Cross the limit and you get a 429 with Retry-After in seconds. Honor it. Retrying immediately turns a short pause into a long one, and the header is telling you exactly how long to wait.

HTTP
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1789459212

Reference

SurfaceDefault limitNotes
POST /verify100 requests a second per keyRaised on request once we see steady traffic.
POST /batches10 submissions a minuteOne batch of 100,000 beats 100 batches of 1,000.
GET /batches/{id}60 a minuteUse a webhook and this stops mattering.
POST /files5 uploads a minuteThe upload is streamed, so this is rarely the bottleneck.

Limits are per key. Separate keys per environment give you separate budgets and a cleaner blast radius.

100,000 addresses, the slow way and the quick way

Say you have 100,000 addresses and your first idea is a loop around POST /verify. At the default 100 requests a second, the sending alone takes about 17 minutes if nothing goes wrong. Each call also holds a connection open while a mail server thinks, and you'll be writing 429 handling for a job that never needed it.

The same list fits in one POST /batches call. That's one request against a limit of ten a minute, and the pacing against mail hosts becomes our problem. Use /verify when a person is waiting on the answer. Reach for a batch when the input is a list.

If you do run many workers on a single key, they share one budget. Each worker sees X-RateLimit-Remaining fall faster than its own traffic explains. Put one shared limiter in front of them all, or give each service its own key.

Backoff, with the arithmetic written out

Say a 429 arrives with Retry-After: 12. Wait the 12 seconds, plus a random extra of zero to three seconds. If the next try also fails, keep the floor at whatever the new header says and widen the random part to six seconds, then twelve. Cap it at five tries and raise an error a person will see.

The random part matters most when you run several workers. Without it, ten workers that were blocked together wake together, and all ten hit the limit in the same instant.

Slow down before you reach zero. When X-RateLimit-Remaining drops under about a tenth of X-RateLimit-Limit, pause until the time in X-RateLimit-Reset. A client that does this rarely sees a 429 at all.

Be careful about which errors you retry. A 402 won't fix itself with waiting, and neither will a 400. One more habit is worth having. Run load tests on a staging key, so the test can't eat the budget your live signup form depends on.

Questions developers ask

What is the right retry strategy?

Exponential backoff with jitter, floor at the Retry-After value. Jitter matters because a fleet that retries in lockstep just recreates the spike.

Does a 429 cost a credit?

No. The request never reached verification, so nothing was spent.

Can I get a higher limit?

Yes, once there is steady traffic on the key to size it against. Ask, and say what shape your load is.

Try it against a sandbox key

Scripted verdicts, no SMTP connections, no credits. Live keys come with 100 free checks a month and no card.