Rate limits
Token bucket limits applied per API key's project during the beta.
Every API key is rate limited using a token bucket — not a fixed per-minute window. That means a key that has been idle can burst above the steady per-minute rate for a moment, then settles back to it, rather than being capped at a hard count that resets on the clock.
Current limits (beta)
The same limits apply to every plan right now — Pro/Enterprise-specific limits are planned but not live yet.
| Bucket | Sustained rate | Burst capacity |
|---|---|---|
| Total | 100 requests / minute | 20 requests |
| Read | 50 requests / minute | 10 requests |
| Write | 50 requests / minute | 10 requests |
A request is checked against both its category bucket (read or write) and the total bucket — the total is a hard ceiling that read and write traffic share, not an additional 100 on top of the 50+50. Reading and writing at the same time can't exceed 100/minute combined, even though each individually has its own 50/minute allowance.
GET /health is excluded from rate limiting entirely — a connectivity
check never counts against your budget.
Scope
Limits are tracked per project, shared across every API key on that project — creating additional keys does not multiply your limit.
Read vs. write
Whether a request draws from the read or write bucket depends on what it
does, not its HTTP method: search-shaped endpoints like POST /v1/search
are reads. See each endpoint's page for its classification, or the
Errors page for the general request lifecycle.
When you're rate limited
A rate-limited request returns 429 with a Retry-After header (seconds
until your next request will succeed):
{ "error": "rate limit exceeded — see your plan's requests/minute limit" }
A rejected request never consumes a token — retrying immediately after
Retry-After elapses works exactly as if the rejected request never
happened.
The TypeScript SDK surfaces this as RateLimitError (err.retryAfter in
seconds) and retries it automatically by default. The Python SDK does not
have a dedicated exception for 429 yet — it surfaces as the underlying
requests.exceptions.HTTPError, with the wait time readable from
err.response.headers.get("Retry-After").