Skip to content
Get API key (opens in a new tab)

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 typeCapacityRefill rate
Reads (GET)25 requests25 requests per second
Writes (POST, PATCH, DELETE)10 requests10 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:

HeaderMeaning
RateLimit-LimitCapacity: 25 for reads or 10 for writes
RateLimit-RemainingWhole requests left in that allowance
RateLimit-ResetRetry delay in seconds on a 429; 0 on successful requests
Retry-AfterSeconds to wait before retrying a 429, rounded up to at least one second

When the read allowance runs out, a read request receives:

429 Too Many Requests
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 25
RateLimit-Remaining: 0
RateLimit-Reset: 1
Retry-After: 1

The 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:

Response body
{
  "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:

fetch-with-retry.ts
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.