Rate limits
Published limits
Each of the three /v1 endpoints is metered against one of two buckets:
| Endpoint | Limit |
|---|---|
GET /v1/catalog, GET /v1/coverage |
120 requests/min per team |
GET /v1/sample |
30 requests/min per team |
/v1/sample carries its own, lower ceiling — it's for judging shape, not
for bulk reads, and the bulk reads belong on /v1/catalog. These are per
key, not per team — two keys on the same team each get their own window.
Limits are published, not discovered: you should never need to hit a 429 to
find out what your ceiling is.
The headers
Every /v1 response carries three headers, whether it succeeds or fails on
rate limits:
RateLimit-Limit: 120
RateLimit-Remaining: 87
RateLimit-Reset: 42
| Header | Meaning |
|---|---|
RateLimit-Limit |
The ceiling for this endpoint group, this minute |
RateLimit-Remaining |
Requests left in the current window |
RateLimit-Reset |
Seconds until the window resets |
Self-throttle before you're throttled
Watch RateLimit-Remaining on every response. When it gets low, sleep for
RateLimit-Reset seconds rather than waiting for a 429:
if int(resp.headers["RateLimit-Remaining"]) < 5:
time.sleep(int(resp.headers["RateLimit-Reset"]))
That keeps a busy integration under the ceiling without ever seeing a failed request.
When you do hit 429
rate_limited is retryable: true. The response carries Retry-After —
honor it. It reflects what the server actually needs, which will always beat
a backoff schedule you invent yourself:
HTTP/1.1 429 Too Many Requests
Retry-After: 42
The pre-auth floor
Failed authentication attempts are also
rate-limited, per source address, independent of any key. This isn't a
catalog limit — it exists so that a flood of made-up keys can't buy unlimited
lookups against the auth store. If you're scripting retries against
invalid_credentials, fix the credential;
don't loop on it.
Limits are published, not discovered.