Rate limits
Check your workspace's read and write limits, read the rate limit headers and retry throttled requests safely.
Each workspace has two independent limits, shared by all its secret API keys:
| Request type | Capacity | Refill rate |
|---|---|---|
Reads (GET) | 25 requests | 25 requests per second |
Writes (POST, PATCH, DELETE) | 10 requests | 10 requests per second |
Every request that passes rate limiting counts once, including requests that later fail validation. Page size does not change the cost. Reads do not use write allowance, and writes do not use read allowance. Creating or rotating keys does not raise either limit.
Allowances refill continuously up to their capacity. A full allowance permits a burst of 25 reads or 10 writes; unused allowance never builds up beyond that. A 429 rejection uses no allowance.
Call GET /v2/me to see the configured capacities in data.rate_limits.reads and data.rate_limits.writes. These values do not report what is left.
Headers and retries
Response headers describe the read or write allowance the request used:
| Header | Meaning |
|---|---|
RateLimit-Limit | Capacity: 25 for reads or 10 for writes |
RateLimit-Remaining | Whole requests left in that allowance |
RateLimit-Reset | Retry delay in seconds on a 429; 0 on successful requests |
Retry-After | Seconds to wait before retrying a 429, rounded up to at least one second |
When the read allowance runs out, a read request receives:
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 25
RateLimit-Remaining: 0
RateLimit-Reset: 1
Retry-After: 1The body uses the shared error shape with the code rate_limit_exceeded. additional_data says which allowance ran out (reads or writes) and repeats the retry delay:
{
"status": 429,
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded",
"request_id": "req_abc123",
"additional_data": {
"rate_limit_class": "reads",
"rate_limit_scope": "workspace",
"retry_after_seconds": 1
}
}Wait at least the Retry-After delay before you retry, and cap the number of attempts. Other requests can use the allowance while you wait, so another 429 is possible:
export async function fetchWithRetry(
url: string,
init: RequestInit = {},
maxAttempts = 3,
): Promise<Response> {
for (let attempt = 1; ; attempt++) {
const response = await fetch(url, init)
if (response.status !== 429 || attempt >= maxAttempts) return response
const seconds = Number(response.headers.get("Retry-After") ?? "1")
await new Promise((resolve) => setTimeout(resolve, seconds * 1000))
}
}Because the limits apply to the whole workspace, coordinate requests across your keys and lower concurrency instead of retrying harder. If throttling persists, contact support with the Cevoid-Request-Id of an affected request. See Debugging requests.