Rate limits
Every response advertises your remaining quota with IETF RateLimit headers. Read them and self-throttle.
The API is rate-limited per principal with a token-bucket limiter: a burst
capacity plus a sustained refill rate. Every response carries the IETF
RateLimit headers so your client can self-throttle before it's ever throttled.
Limits are keyed on the principal — the API key or the user — never on IP address. The limiter is DoS and cost protection; row-level security remains the real access boundary.
Response headers
Every response (including 429s) includes:
RateLimit: "default";r=27;t=2
RateLimit-Policy: "default";q=30;w=15| Field | Meaning |
|---|---|
RateLimit r | Requests (tokens) remaining right now. |
RateLimit t | Seconds until the bucket is full again. |
RateLimit-Policy q | The quota — the bucket's burst capacity. |
RateLimit-Policy w | Seconds it takes an empty bucket to refill to q. |
These follow the IETF RateLimit header fields draft. Read r and back off as
it approaches 0. Note that w is not a fixed calendar window: tokens
refill continuously, so q over w gives the sustained rate (e.g. q=30,
w=15 refills two requests per second).
When you're limited
Over the limit, the API returns 429 rate_limited (an
RFC 9457 error) with a Retry-After header giving whole seconds
to wait, alongside RateLimit (r=0) and RateLimit-Policy:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
RateLimit: "default";r=0;t=15
RateLimit-Policy: "default";q=30;w=15
Content-Type: application/problem+jsonRetry-After is the wait (whole seconds, minimum 1) until the next request
can be served — usually short, because tokens refill continuously. Honor it,
then retry. Well-behaved clients watch the RateLimit header and slow down
before hitting 429 at all.
Quotas
Quotas depend on the principal class. Current burst / sustained limits:
| Principal | Burst (q) | Refill window (w) | Sustained (per minute) |
|---|---|---|---|
Gallery key (gpk_) | 30 | 15s | ~120 |
Org key (opk_) | 60 | 12s | ~300 |
| First-party app user | 100 | 10s | ~600 |
| External user token | 40 | 12s | ~200 |
Treat these as the current values, not a contract — the authoritative,
per-response numbers are always the RateLimit / RateLimit-Policy headers.
Limiter unavailable
If the limiter must run but can't, the API fails closed with
503 service_unavailable and Retry-After: 5 rather than letting an unmetered
request through. Retry after the indicated delay.