DevelopersRate limits

Rate limits

Two limits apply to the public API, both counted per key and per minute. They are deliberately loose: they exist to stop a loop running away, not to meter your usage. What your plan actually meters is a separate thing, and it answers with a different status.

The limits

60 per minute
Write operations on /api/v1. That is the seven POST and PATCH operations, counted together rather than per endpoint.
120 per minute
JSON-RPC requests to the MCP endpoint, counted separately from the write limit.
No limit
The two read operations, GET /contacts and GET /sequences. Neither passes through the limiter at all.

Both counters are keyed on the API key, not on the workspace, the IP or the user. Two keys in one workspace therefore have two independent budgets. That is a consequence of how the counter is keyed rather than a licence to shard around the limit: if you need materially more throughput than this, the limit is the wrong thing to work around and we would rather hear about the use case.

What a limited request looks like

You get a 429 carrying the standard error envelope with the code rate_limited, and a Retry-After header giving whole seconds to wait. Retry-After is never less than one second, so it is always safe to sleep for the value you are given.

429 Too Many Requests
Retry-After: 12{ "data": null, "error": "Rate limit exceeded.", "code": "rate_limited" }

The API does not send X-RateLimit-Limit, X-RateLimit-Remaining or X-RateLimit-Reset. There is no way to read your remaining budget before you spend it, so a client that needs to stay under the limit should pace itself rather than watch a counter. Retry-After on a 429 is the only rate-limit signal on this surface.

Treat the limit as approximately enforced rather than exact. It is a protective control against runaway loops, not a security boundary or a billing meter, and it is implemented accordingly. Do not build a client that depends on getting exactly sixty writes through in a given minute.

The other 429, which is not a rate limit

Creating a contact can also return 429 for an entirely different reason: the workspace has reached the contact allowance on its plan. This is a plan cap, not a throughput limit, and waiting will not clear it.

Read the code to tell them apart. A throughput limit answers with code rate_limited and a Retry-After header. A plan cap answers with a code beginning quota_exceeded, carries no Retry-After, and includes a quota block describing the allowance you have hit. Retrying a plan cap on a backoff loop will simply fail until somebody changes the plan.

There is a third refusal in the same family and it is a 402 rather than a 429: a workspace that is read-only because a trial expired, a financed term elapsed, or an account went delinquent. That one refuses every write except adding to the suppression list. A client handling billing states should branch on 402 and quota_exceeded separately from rate_limited, because only the last of the three is worth retrying.

Staying under them

  • Honour Retry-After rather than retrying immediately. A tight retry loop against a limiter spends your next window on requests that are refused.
  • Send an Idempotency-Key on writes. Then a retry after a 429, or after a timeout where you never saw the response, cannot create a duplicate record.
  • Reads cost you nothing against the write limit, so reconciling what already exists before writing is free.
  • Back off exponentially on repeated 429s, and stop retrying entirely once the code is not rate_limited.

Limits on the delivery side

These limits are about requests you make to us. Requests we make to you, when a webhook fires, have their own bounds: each POST is given 10 seconds, and a delivery is attempted six times before it is dead-lettered. Those are described on the Webhooks page.

Behaviour on this page is read from

  • src/lib/public-api-auth.ts
  • src/lib/rate-limit.ts
  • src/lib/mcp/server.ts
  • src/app/api/v1/contacts/route.ts
  • src/app/api/v1/sequences/route.ts
  • src/lib/billing/api-write-gate.ts
  • src/lib/billing/usage-quota-guard.ts
  • src/lib/webhooks/webhook-delivery.ts

Was this page helpful?

Book a demo