Rate limits
10 requests per second per team, shared across every API key the team holds. Four headers tell you where you stand.
The limit
The bucket holds 10 tokens and refills at 10 a second, so a short burst of 10 is fine and a sustained rate above 10 a second is not.
The limit is per team, not per key. Creating a second API key does not buy more capacity — every key on the team draws from the same bucket.
The headers
| Header | Meaning |
|---|---|
ratelimit-limit | The ceiling, 10. Constant, on every response. |
ratelimit-remaining | How many requests are left in the bucket right now. |
ratelimit-reset | Seconds until the bucket is full again. |
retry-after | Whole seconds to wait. Present only on a 429, and never zero. |
The first three are on every response, successful or not, so you can slow down before you are refused rather than after.
Being refused
HTTP/1.1 429 Too Many Requests
ratelimit-limit: 10
ratelimit-remaining: 0
ratelimit-reset: 1
retry-after: 1
{
"statusCode": 429,
"name": "rate_limit_exceeded",
"message": "Too many requests."
}- Wait for
retry-afterseconds, then retry. It is never zero, so a client that multiplies it can always make progress. - Add jitter. Several workers that all wait exactly one second will collide again one second later.
- Use an
Idempotency-Keyon sends, so a retry after a refusal cannot become a second email.
Sending a lot at once
POST /emails/batch is one request for up to a hundred messages, which is one token rather than a hundred. If you are being rate limited by a loop over individual sends, a batch is the fix.