Call Lens
Going live

Rate limits

Four buckets stack on an identified request, and the tightest one binds.

On a request that presents a readable API key, rate limits are per key — not per organization and not per IP — so one integration cannot throttle another, and minting a second key gives you a second budget. A request whose credential cannot be parsed at all is the one exception, and the last row below is what bounds it.

The buckets

BucketLimitApplies to
Plane ceiling600 / minuteevery endpoint
Plane burst20 / secondevery endpoint
Upload presign10 / minutePOST /uploads
Webhook test6 / minutePOST /webhooks/{id}/test
Unidentified60 / minuteper IP, when no API key can be parsed from the request

The first four stack, and the tightest one binds. A presign request consumes a plane slot and an upload slot. Reading "600 per minute" and batching uploads will hit 429 at ten — this is the most common surprise on this API.

The last bucket does not stack with the others and no working integration ever meets it. A request carrying no clk_… credential, or a malformed one, has no key to bucket by, so it is bucketed by address instead — and it was going to 401 whatever the limiter decided. It exists to stop a host looping on a 401, not to bound your traffic.

These are the shipped defaults. The plane ceiling of 600 per minute can be raised for an individual organization by an operator; the burst clip and the two route ceilings are global settings, so changing them moves the limit for everyone. Response headers report the bucket that actually bound, so trust them over any number on this page.

Why the two route limits are lower

They are not load limits, and knowing what they are predicts when you will meet them.

POST /uploads is a spend bound. Every object that lands becomes a transcription the organization is billed for. The bucket is sized for money, not for CPU — which is why it is far below the plane ceiling even though presigning is cheap.

POST /webhooks/{id}/test is a security bound. It is the only route that makes Call Lens open an outbound connection to an address you chose. At 600 per minute it would be an amplifier.

Handling a 429

A throttle response carries a Retry-After header and the bare body:

{ "message": "Too Many Attempts." }

Wait for Retry-After, then retry. Exponential backoff with jitter is fine on top.

Check for an error key first. On POST /calls a 429 can also be an allowance refusal carrying the full envelope and no Retry-After — and ai_budget_exhausted will never clear on its own. See errors.

Staying under the limits

  • Presign at the rate you actually upload; do not pre-allocate tickets in bulk.
  • Submit calls as they finish rather than in a nightly batch — a day of calls arriving in one minute meets the burst clip even when the daily total is small.
  • Test a webhook endpoint when you change it, not on a schedule. Use real deliveries to confirm it is healthy.
  • Treat 429 as backpressure, not as an error to alert on. Alert on the codes that will not clear.

On this page