Rate limits
The API is rate-limited per organisation. Read the headers and retries become boring.
The limit
- 100 requests per second per organisation, with a burst of 100. Token-bucket policy.
- The limit is shared by every API key in the organisation. If you need more, talk to us before sharding keys.
- Sandbox and live each get their own budget. A tight retry loop in sandbox cannot exhaust your live quota.
A second limit: failed passphrase exchanges
- 10 failed passphrase exchanges per organisation per hour on
POST /api/v1/recipient-accounts. The next attempt returns429 rate_limitedwithRetry-After: 3600- at most an hour, since the window rolls and the wait is really until the oldest counted failure ages out. A correct passphrase is refused too while the window holds. - The budget is shared with the in-app form at
/engage/recipients/add, because a distribution passphrase is a credential and the limit exists to stop it being guessed. Failures from either surface count against the same hour. - A refused attempt does not extend the window, so backing off for an hour always clears it. Re-POSTing a passphrase you already hold an active link to is not counted either, so a retry loop on your own link cannot lock you out. Nothing else on the API carries a per-endpoint limit.
- This limiter carries no
RateLimit-*headers of its own - those describe the per-second bucket above. ReadRetry-After.
Headers on every response
We emit both the IETF draft-10 RateLimit-* family and the older X-RateLimit-* family. Use whichever your tooling understands. One exception: the failed-passphrase 429 above carries no header from either family - only Retry-After - because these describe the per-second bucket and not that limit.
| Header | Meaning |
|---|---|
| RateLimit-Limit | Requests allowed in the window. |
| RateLimit-Remaining | Requests remaining in the current window. |
| RateLimit-Reset | Seconds until the window resets (relative). |
| RateLimit-Policy | 100;w=1;policy="token bucket". |
| X-RateLimit-Limit | Same as RateLimit-Limit. |
| X-RateLimit-Remaining | Same as RateLimit-Remaining. |
| X-RateLimit-Reset | Unix epoch (seconds) when the window resets (absolute). |
When you are throttled
Exceeding the limit returns 429 rate_limited with a Retry-After header (seconds):
HTTP/1.1 429 Too Many Requests
Retry-After: 1
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 1
{
"error": {
"type": "https://alltogether.giving/developer/api/errors/rate_limited",
"code": "rate_limited",
"message": "Too many requests. Slow down and retry after the window resets.",
"request_id": "req_..."
}
}- Sleep for
Retry-Afterseconds, then retry. - Pair the retry with an Idempotency-Key so the eventual successful call cannot double-write.
- If you're consistently hitting the ceiling, add backpressure on the client side. A bounded queue and a worker pool with concurrency below 100 is usually enough.
Staying under the ceiling
- Watch
RateLimit-Remainingon every response. Pause bulk jobs when it drops below a threshold you pick. - Filter server-side rather than fetching and filtering in the client. Every endpoint supports bracket filters and pagination.
- For large exports, walk pages in series. Parallel exports against the same organisation will just burn your burst.
Rate limits are per organisation, not per API key. Spinning up more keys for the same organisation does not raise the ceiling.
Related
- Error envelope and codes: the shape of
rate_limited. - Idempotency: safe retries after a 429.