Valori LogoValori

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.

BucketSustained rateBurst capacity
Total100 requests / minute20 requests
Read50 requests / minute10 requests
Write50 requests / minute10 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").