Every response carries your current standing:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
X-RateLimit-Reset: 1754231400
Limits are counted per API key. Requests that never resolved a key are limited per IP address at a much tighter rate, which is what a key-guessing loop runs into.
| Tier | Requests per minute |
|---|---|
| Standard | 300 |
| Elevated | 1200 |
| Unauthenticated | 60 |
Contact us if your integration needs the elevated tier.
Signing in as a person
The app endpoints count separately, because the thing being protected is different: a sign-in attempt is worth guessing at, and an open inbox polls.
| What | Limit |
|---|---|
| A signed-in device | 600 requests a minute, per device |
| Resolving an environment | 30 a minute, per address |
| Signing in | 10 attempts per 10 minutes per address, and 5 per email |
| Answering a two-factor challenge | 20 per 10 minutes per address, and 10 per challenge |
The per-device limit means one person hammering their inbox never slows down a colleague on the same office connection. A two-factor challenge is also spent after five wrong codes regardless of the limit above.
When you go over
You get 429 with rate_limit_exceeded and a Retry-After header in seconds:
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Too many requests. Slow down and retry after the window resets.",
"request_id": "req_01kz4bkr1aj1gv63d8fv3133ey"
}
}
Back off, do not hammer
Wait at least Retry-After seconds, then retry with exponential backoff. Retrying
immediately in a loop only keeps you rate limited for longer.
Because limits are per key rather than per IP, one noisy integration cannot throttle a different firm that happens to share an outbound address.