Plans and limits
Rate limit buckets, response headers, quotas, and the plan table.
Request volume is bounded per brandspace: every API key that brandspace has issued shares the same limits (there is no separate per-key sub-limit).
Buckets
| Bucket | Window | Counts against it |
|---|---|---|
burst | per second | Every request. |
sustained | per minute | Every request. |
search | per minute | GET /v1/search, GET /v1/files when called with q, GET /v1/files/:id/similar, POST /v1/boards/:id/query when called with q. |
uploads | per day | Upload initiations (POST /v1/uploads), file imports (POST /v1/files/import). |
downloads | per day | POST /v1/downloads, GET /v1/files/:id/download. |
| monthly quota | calendar month | Every request. |
Response headers
Every /v1 response carries:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset— the sustained (per-minute) window, in epoch seconds.X-Quota-Limit,X-Quota-Remaining,X-Quota-Reset— the monthly quota.
A rejection still carries all six headers, whichever specific bucket was actually denied,
plus Retry-After and one of:
429 rate_limited—details.bucketnames the bucket that was hit.429 quota_exceeded— the monthly request quota is used up.
Plan table
API access starts at Lite; Free has no API access at all and answers
403 plan_without_api with details.upgrade_url. These limits are data, not code — they
change without a deploy, so treat the table below as a guide and GET /v1/me (see
Getting Started) as the source of truth for your own brandspace.
| Lite | Pro | Growth | Custom | |
|---|---|---|---|---|
| Burst (req/s) | 2 | 10 | 25 | contract |
| Sustained (req/min) | 30 | 300 | 1,000 | contract |
| Monthly requests | 1,000 | 100,000 | 1,000,000 | contract |
| Upload initiations / day | 20 | 2,000 | 20,000 | contract |
| Download URL issuances / day | 100 | 10,000 | 100,000 | contract |
| Search (NL) / min | 2 | 30 | 120 | contract |
| Active keys | 1 | 5 | 20 | contract |
| Webhook endpoints | 1 | 3 | 10 | contract |
| Request-log retention (days) | 7 | 30 | 90 | contract |
When the limiter is unavailable
If the counter store is unreachable, requests are allowed through rather than blocked — a
counter outage should never take the whole API down. The one exception is authentication
itself: a database outage while a key is being resolved always answers 500 internal_error, it never fails open.
Failed-authentication throttling
Independent of the buckets above: every request whose key fails to authenticate (any
401 api_key_* outcome) counts against a per-IP counter in a rolling 5-minute window. At
20 failures, that IP gets 429 rate_limited (details.bucket: "auth") without the key
even being looked up, until the window resets. Only failures count — a valid key from the
same IP is never throttled by this counter.