Rate limits

Headers on every response

The API limits how often a client can call it. Cross the limit and the response is a 429 with the code RATE_LIMITED. A rate-limited request never reaches verification, so nothing is billed.

Every response carries two headers that describe the limit: X-RateLimit-Limit is the number of requests allowed, and X-RateLimit-Window-Seconds is the length of the window that count applies to. Read them instead of hard-coding a figure, because the numbers can change.

There is no Retry-After header. When you get a 429, wait for the length of the window and then continue, and add some jitter so a fleet of clients does not retry in lockstep and rebuild the spike.

HTTP
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Window-Seconds: 60
X-Request-Id: req-8f2c1d

{"statusCode":429,"code":"RATE_LIMITED","message":"Too many requests","requestId":"req-8f2c1d"}

Reference

HeaderMeaning
X-RateLimit-LimitRequests allowed in one window.
X-RateLimit-Window-SecondsThe window length, in seconds.
X-Request-IdA unique id for this request. Quote it when you contact support.

The default allowance is 120 requests per 60-second window. Read the headers rather than assuming it.

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 /v1/verify, which takes 20 per call. That's 5,000 requests, and at the default 120 requests per 60 seconds the sending alone takes about 42 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 two POST /v1/jobs calls of 50,000 each. That's two requests against the window, and the pacing against mail hosts becomes our problem. Use /v1/verify when a person is waiting on the answer. Reach for a job when the input is a list.

If you do run many workers on a single key, they share one budget. Each worker sees 429s sooner 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 X-RateLimit-Window-Seconds: 60. There is no Retry-After header, so wait the length of the window, plus a random extra of zero to three seconds. If the next try also fails, keep the floor at the window 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.

Be careful about which errors you retry. A 422 CREDITS_INSUFFICIENT won't fix itself with waiting, and neither will a 400. A 429 and a 422 NO_CAPACITY are the ones worth another try. One more habit is worth having. Run load tests from a key of their own, 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, with the floor set to the window length from X-RateLimit-Window-Seconds. Jitter matters because clients that retry together recreate the spike.

Does a 429 cost a credit?

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

Can I get a higher limit?

Ask support, and say what shape your traffic has. A bulk workload is better served by jobs than by a higher request limit.

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.