Rate limits
Budgets follow the credential, never the network. Each API key, app install and OAuth connection gets its own per-minute budget, so one workspace’s integrations never throttle each other — and a valid credential behind a shared office NAT, a VPN or a Zapier worker pool is judged on its own, not on its neighbors.
The budgets
All budgets are per minute, per credential. They are sized to be invisible to a real integration: a nightly sync paging ten thousand contacts at 100 rows a request is a hundred reads, done in seconds, well inside the read budget.
| Budget | Ceiling | What spends it |
|---|---|---|
| read | 300 / min | Every GET: the whoami read (GET /api/v1), catalog discovery (GET /api/v1/actions), action descriptions, resource lists, webhook subscription reads. |
| write | 120 / min | Action execution (POST /api/v1/actions/<name>), MCP tool calls, resource writes, webhook subscription changes. Two a second sustained — and the ceiling that bounds a runaway loop before it spends real money. |
| llm | 20 / min | Assistant chat turns. Each one is a paid model call, and twenty turns a minute is already faster than anyone reads their own answers. |
| unidentified | 120 / min per IP | Requests that resolve to no credential at all — absent, malformed, unknown or revoked tokens. This is the only per-address budget; anything that authenticates is keyed on its own credential and never touches it. |
“Per credential” is precise: the budget is keyed on the API key’s id, the app install’s id, or the OAuth connection (the grant, which survives token refreshes) — so presenting one key from ten addresses shares one budget, and refreshing an access token every hour changes nothing.
The headers
Every /api/v1 response advertises its budget in the IETF draft-standard RateLimit-* form:
| Header | Meaning |
|---|---|
| RateLimit-Limit | The ceiling that applied to this request. |
| RateLimit-Remaining | Budget left in the current window. Treat it as a best-effort upper bound for pacing — the refusal decision itself is exact. |
| RateLimit-Reset | Seconds until the window resets — a delta, not a timestamp. Windows align to the wall clock, so every caller sees the same boundary. |
| Retry-After | On a 429 only: how many seconds to wait. This is the header retry libraries honor automatically. |
What a 429 looks like
RateLimit-Limit: 120
RateLimit-Remaining: 0
RateLimit-Reset: 41
Retry-After: 41
{ "error": { "code": "rate_limited",
"message": "Too many requests. Slow down and retry after the interval in the Retry-After header." } }The OAuth token endpoint is the one exception: it answers its 429 in the RFC 6749 shape — { "error": "slow_down", … } — with the same headers, so OAuth libraries parse it natively. See Errors.
Unidentified callers and the fast refusal
A request whose credential does not resolve is answered 401 and charged to its address’s per-IP budget — that ceiling is what bounds credential guessing. An address that has spent that budget is refused up front, before any credential lookup runs, until its window resets. Two properties keep this fair to bystanders:
- A credential that authenticates is always judged on its own id — a valid integration keeps working even while something else behind the same NAT is misbehaving.
- The limiter fails open: a fault in it yields the response you had coming, never a new failure mode.
Building a polite client
- Honor
Retry-Afteron every 429, and watchRateLimit-Remainingto pace bulk work instead of discovering the ceiling by hitting it. - Page at
limit=100— the maximum — so large reads spend the fewest requests. - Spread bulk writes. A queue draining two writes a second sustains the full write budget forever; a burst of thousands should trickle, not race.
- One credential per integration. Budgets are per credential, so giving each integration its own key isolates their pacing — and their blast radius when one is revoked.
- Stop on repeated 401s. A revoked credential answers the same way every time; alert a human instead of retrying into the per-address budget.
- Prefer webhooks to polling. A webhook subscription delivers each event once, signed — no read budget spent asking whether anything happened.
Growing past the ceilings
The budgets above accommodate every integration pattern we see, including full-workspace syncs. If yours genuinely needs more, tell us what you’re building — file it from the API itself with POST /api/v1/actions/support.request_feature or write in from the app — and we’ll size it with you.

Chirply