Rate limits
Rate limits protect the platform from a single integration monopolising it, and protect you from a runaway loop burning your quota. Every budget below is counted per API key; the minute budgets are also capped for the account as a whole, so minting more keys does not multiply capacity. Test keys draw from a ceiling of their own, so test traffic never spends the live budget.
Why several budgets and not one
A single limit forces everything to compete: a nightly import of 5,000 documents would starve the live chat traffic that customers are waiting on. Separate budgets mean the expensive, bursty work and the latency-sensitive work cannot exhaust each other.
Generated from the API's own description of its limiters, with the budgets a default deployment ships. Each endpoint in the API reference lists the limiters it passes. Reading that table:
- Per minute budgets are fixed windows: the window opens with the first request and resets a minute later. Spending evenly beats sending everything in the first second.
- Per second is a burst brake. It stops a fast loop before the per-minute
budget notices, and it also applies to
GET /v1/statusandGET /v1/openapi.json, which need no key. - The write budget applies to mutations plus a few expensive reads (semantic search runs a real retrieval pass, so it is metered like a write), on top of the general budget.
- The chat budget is separate because a chat turn costs a message credit as well as a request.
- Failed authentication is counted per client IP. A valid key is never refused by it, so a neighbour on a shared network guessing keys cannot lock you out.
- A per-key limit set when you create a key can only lower that key's general budget, never raise it.
Backfills and imports on their own key keep their requests apart in the request log, so you can see which workload caused a spike, and a per-key limit on the bulk key stops it from crowding out interactive traffic.
What a 429 looks like
{
"message": "Too many requests. Please try again in 12 seconds.",
"retry_after": 12,
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please try again in 12 seconds.",
"details": { "retry_after": 12 }
},
"request_id": "483c1c5107978d552c8f634d8b141501"
}The response also carries Retry-After (the same number of seconds),
X-RateLimit-Limit (the budget that was exhausted) and
X-RateLimit-Remaining: 0. If the rate-limit store itself is briefly
unavailable, the API refuses rather than letting traffic through unmetered:
you get the same 429 with Retry-After: 5.
Handling it
- Read Retry-After (seconds). It is not a suggestion — retrying sooner keeps you limited for longer.
- Sleep at least that long, plus a little random jitter so a fleet does not retry in lockstep.
- Retry the same request, with the same Idempotency-Key on any mutation.
- If you are hitting 429s steadily rather than in bursts, the fix is fewer requests, not faster retries.
# --retry handles the sleeping for you; --retry-all-errors covers 429.
curl --retry 5 --retry-delay 2 --retry-all-errors \
https://api.agentency.com/v1/chatbots \
-H "Authorization: Bearer <YOUR_KEY>"The official SDKs do all of this already — see SDKs.
Staying under the limit
- Page with a sensible
limit. One request for 100 rows beats a hundred requests for one. See Pagination. - Subscribe instead of polling. A webhook costs you zero requests; a poll loop checking training status every second costs 3,600 an hour and mostly learns nothing. See Webhooks.
- Cache what does not change. Chatbot settings and scope catalogues do not need refetching per operation.
- Batch where the API allows it. File uploads accept
files[].
Immediate retries without backoff turn a momentary limit into a sustained one, because each retry consumes budget that would otherwise have refilled. Always sleep, and always add jitter.
Higher limits
If a legitimate workload does not fit, get in touch through Support with your key id, the endpoints involved, and the throughput you need. It is usually a fast conversation.
What's next
- Errors — which failures are worth retrying.
- Idempotency — how to retry safely.
- Going live — the production checklist.