Rate limits

The request budget of the capability API, the shape of a 429, and how to back off.
View as Markdown

The /v1 API allows at least 67 requests per minute per organization. This is a guaranteed floor, not a hard global ceiling. Enforcement happens per edge location and is eventually consistent. A geographically distributed caller can sustain more before the API limits it.

The limit is shared across every /v1 endpoint. Extract, parse, redact, fill, sign, pipelines, files, runs, templates, actions, and webhook management all draw from the same per-organization budget.

The limit is scoped to your organization, not your key. Every organization API key in the same organization draws from one budget. One organization that exhausts its budget never affects another. A second key does not buy more throughput.

What counts as one request

One HTTP request costs one token, regardless of the work it starts. A batch that fans out to 100 documents costs the same single token as a one-file call. This makes batching the cheapest way to stay under the limit at volume. Long-polling with ?wait= also costs one token, no matter how long the call is held open. Waiting for a run is cheaper than polling it.

GET /v1/webhooks/jwks.json is the one exception. It is public, unauthenticated, and never rate limited. Rate limits can therefore never block key rotation.

When you exceed it

You get 429 with the standard error envelope and a Retry-After header in seconds:

1HTTP/2 429
2content-type: application/json
3retry-after: 60
4x-request-id: req_01KYDQJBG32QDWHM5ERG63XGNE
1{
2 "code": "rate_limited",
3 "message": "Rate limit exceeded: 67 requests per minute per organization. Retry after 60 seconds.",
4 "retryable": true,
5 "requestId": "req_01KYDQJBG32QDWHM5ERG63XGNE",
6 "docUrl": "https://docs.cloudraker.com/developers/rate-limits"
7}

A 429 starts nothing. It never creates a run and is never billed. You can safely replay the identical request.

How to retry

  1. Respect Retry-After first. It is the authoritative wait in seconds. Sleep at least that long before the next attempt. Do not compute your own delay when the header is present.
  2. Then back off exponentially on repeated 429s: 60 s, 120 s, 240 s, with jitter. Jitter prevents a fleet of workers from resynchronizing into the next window together.
  3. Cap your concurrency instead of retrying harder. A steady ~1 request per second per organization never hits the floor.
  4. Send an Idempotency-Key on writes. A retry that crosses with a slow success then returns the original run instead of starting a second one. The one exception is POST /v1/extract/batch, which ignores the header. One key cannot address N runs, so a retried batch fans out again. Track batches by metadata instead.

An immediate retry on 429, or a tight loop without jitter, keeps you limited for longer. retryable: true means the same request can succeed later. It does not mean the request can succeed now.

Staying under the limit

  • Batch instead of looping. POST /v1/extract/batch turns 100 calls into one.
  • Use webhooks instead of polling. A terminal event costs you zero requests. Polling a slow run costs one per check.
  • Long-poll when you must poll. GET /v1/runs/:id?wait=30 holds one request open instead of spending 30.
  • Reuse file ids. Register a document once and re-run against {"id": …}. This avoids re-parsing and extra calls.

If you need a higher ceiling for a launch or a backfill, talk to your CloudRaker contact with your expected peak. Every organization gets the floor above without asking.

Where to go next