Rate Limits
Every /v1 request is rate limited per API key using a sliding 60-second window. Your ceiling depends on your plan. A rejected request does not count against you — backing off always lets you recover.
Limits by plan
| Plan | Limit |
|---|---|
| Free | 60 requests / minute |
| Pro | 300 requests / minute |
| Enterprise | 10,000 requests / minute |
The window is a true sliding window keyed on your API key — not a fixed bucket that resets on the minute. Need a higher ceiling? Talk to us.
Rate-limit headers
Every response — success or 429 — carries your current budget, so you can throttle proactively instead of waiting to be rejected.
| Header | Description |
|---|---|
X-RateLimit-Limit | Your plan's ceiling for the current window. |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | Unix time (seconds) when the window frees up. |
When you exceed a limit
Over the limit, the API returns 429 with code rate_limited. The details.resetAt field (also the X-RateLimit-Reset header) tells you when the window frees up, in unix seconds.
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Limit: 300 requests/minute",
"details": {
"limit": 300,
"remaining": 0,
"resetAt": 1717000060
},
"requestId": "req_xyz123"
}
}Backing off
Catch the rate_limited error, wait until resetAt, then retry. For a general transient-error retry helper, see Errors → Retrying.
// On a 429, the error's details carry resetAt (unix seconds) — when the
// window frees up. Wait until then, then retry.
try {
await agent.run('analyze the data')
} catch (err) {
if (err instanceof TheazoError && err.code === 'rate_limited') {
const resetAt = Number(err.details.resetAt) // unix seconds
const waitMs = Math.max(0, resetAt * 1000 - Date.now())
await new Promise((r) => setTimeout(r, waitMs))
await agent.run('analyze the data') // retry after the window resets
} else {
throw err
}
}Related limits
Two other kinds of limit are separate from this request throttle:
- Resource limits — a session's
maxAgentsormaxCost, or a fleet's cost cap. These returnsession_limit_exceededand won't clear by retrying — raise the limit or wait for the resource to free up. - Public channel widgets — the unauthenticated widget endpoints have their own per-channel, per-visitor, and per-IP limits (abuse protection), independent of your API key's plan limit.
X-RateLimit-Remaining and slow down as it approaches zero. It's cheaper than a rejected request and keeps your throughput smooth.