Skip to content

Rate limits

Prefactor rate limits requests to the platform API so that one busy integration cannot degrade the service for everyone else. This page lists how limits are applied and what a limited response looks like. If you use the TypeScript or Python SDK, retries are handled for you — see Handle rate limiting.

Every HTTP request counts against a high per-IP ceiling that exists to absorb floods. Authenticated requests count against additional scopes, checked over fixed one-minute windows. Which scopes apply depends on the token: an account token counts against the token itself and the account; a deployment token counts against the token, its agent deployment, its agent, and the account.

A single request counts against every applicable scope at once, and exceeding any one of them limits the request. Reads (queries) have a higher allowance than writes (actions) and live subscriptions. The same limits apply to every account.

The web app and login are not rate limited beyond the per-IP ceiling.

A limited HTTP request returns status 429 with a Retry-After header in whole seconds and a JSON body:

{
"status": "error",
"code": "rate_limited",
"message": "Rate limited on the API token",
"retry_after_ms": 1500
}
FieldTypeDescription
statusstringAlways "error".
codestringAlways "rate_limited".
messagestringNames the scope that was exceeded — for example, “Rate limited on the account”.
retry_after_msintegerMilliseconds to wait before retrying.

Retry-After and retry_after_ms carry the same wait; use either.

The WebSocket API (/api/v1/ws) speaks JSON-RPC, so a limited call returns a JSON-RPC error with code -32000 instead of an HTTP status. The error’s data object carries the same fields as the HTTP body above.