Rate limits
Requests are metered with distributed token buckets. Several apply at once, and the strictest one wins.
| Bucket | Applies to | Quota |
|---|---|---|
client | Every data-plane request, per credential | 120/min, adjustable per credential |
company | Every data-plane request, across all credentials of the company | 600/min |
transcript | Transcript reads only, on top of the two above | 60/min |
oauth-client | POST /oauth/token, per client id | 10/min |
oauth-ip | POST /oauth/token, per source IP | 30/min |
A company may hold up to 20 active credentials, and together they never exceed
the company quota. Call GET /v1/context to read the credential quota actually
in effect for yours.
Headers
Section titled “Headers”Every response carries the current state. RateLimit-Policy lists every bucket
the request consumed; RateLimit reports the single one closest to exhaustion:
RateLimit-Policy: "client";q=120;w=60, "company";q=600;w=60RateLimit: "client";r=118;t=1q is the quota, w the window in seconds, r what is left and t the seconds
until another token. RateLimit names whichever bucket is holding the fewest
tokens: normally your credential’s, the transcript one on transcript reads, and
the company one once sibling credentials are spending it. Pace against the
ceilings in RateLimit-Policy — the bucket named in one reading is not the only
one binding you.
r counts tokens in the bucket, whose capacity is the burst rather than the
quota, so it does not start at q and count down. Treat it as room available
right now.
A rejected request returns 429 RATE_LIMIT_EXCEEDED with Retry-After in
seconds. Wait that long — do not retry immediately, and add jitter so a fleet of
workers does not resynchronise into the next window.
Behaviour when the limiter is degraded
Section titled “Behaviour when the limiter is degraded”Read paths fail open: if the limiter is briefly unreachable, business reads keep serving rather than going dark.
Token issuance, transcript reads and internal control-plane routes fail
closed with 503 SERVICE_UNAVAILABLE. These are the paths where serving
unmetered traffic is worse than serving none.
The WAF limit is separate
Section titled “The WAF limit is separate”A coarse per-IP limit runs at the WAF, before traffic reaches the service, and it
is not part of the quotas above: roughly 2000 requests per five minutes per
source IP, and 100 per five minutes on /oauth/token.
It fails differently, which matters when you meet it:
- it blocks with
403, not429, so it reads as an authorization failure; - there is no error code, no
Retry-Afterand no rate limit headers, because the request never reaches the service; - it counts by source IP, so every integration behind the same egress address shares it, whatever credentials they use.
A 403 with none of our error body, especially on /oauth/token, is this limit
rather than a missing scope.
Staying under the limit
Section titled “Staying under the limit”- Page with
limit=100instead of many small pages — one request returns up to 100 records at the same cost as one returning 10. - Filter by period rather than walking the whole history repeatedly.
- Cache the access token; every
/oauth/tokencall consumes its own bucket. - Fetch transcripts only for records you will actually process.
has_transcriptlets you filter the list first.