Appearance
Rate limits
Limits are enforced per team, not per key.
That's deliberate. All of a team's keys sit in front of the same sending reputation, so minting a second key can't double what you push at it. It also means the numbers you see are the numbers that matter — a key can be given a tighter limit than its team (handy for one you hand to a partner), but never a looser one.
| Window | Default |
|---|---|
| Per second | 10 requests |
| Per day (UTC) | 10,000 requests |
Both can be raised — ask us once you have a sending history to point at.
Every response tells you where you stand
You don't have to hit a limit to find out about it. Every response carries your remaining budget:
http
RateLimit-Limit: 10
RateLimit-Remaining: 7
RateLimit-Reset: 1
RateLimit-Daily-Limit: 10000
RateLimit-Daily-Remaining: 9863
RateLimit-Daily-Reset: 58685| Header | Meaning |
|---|---|
RateLimit-Limit | Requests allowed in the current second. |
RateLimit-Remaining | How many are left in it. |
RateLimit-Reset | Seconds until that window resets. |
RateLimit-Daily-Limit | Requests allowed today. |
RateLimit-Daily-Remaining | How many are left. |
RateLimit-Daily-Reset | Seconds until 00:00 UTC. |
The daily window gets its own headers rather than hiding behind the per-second one. It's the limit that actually ends someone's evening, and a client that can see it coming can slow down instead of falling over.
When you exceed one
429, with the reason in code and a Retry-After in seconds:
json
{
"message": "Rate limit of 10 requests per second reached for this team.",
"code": "rate_limit_exceeded",
"request_id": "8f2c1e64-1b17-4f8c-9f0e-3b6c1e0f5c31"
}json
{
"message": "Daily quota of 10000 requests reached for this team. It resets at 00:00 UTC.",
"code": "daily_quota_exceeded",
"request_id": "3b6c1e0f-5c31-4f8c-9f0e-8f2c1e641b17"
}A 429 still carries the full set of RateLimit-* headers, so a backoff loop can read its budget from the very response that rejected it.
Handling it
Wait Retry-After seconds and retry. Don't retry immediately, and don't retry a burst all at once — the second window is one second wide, so a stampede of retries just re-triggers it.
If you regularly hit the per-second limit, the fix is usually a queue between your app and us rather than a higher limit. If you're sending a large run, use batch: 100 messages in one request costs one request against your budget, not 100.