# Limits

Every limit a developer can hit, from the runtime's code. Sizes: KiB = 1024
bytes, MiB = 1024 KiB. Past a size limit the request is refused (400 or 413);
past a count or rate limit, 409 or 429 (with `Retry-After`). See
[Errors](errors.md) for what to do about each.

## Rate limits

Past one, the API answers 429 with `code: "RATE_LIMITED"`, `Retry-After` (in
seconds), and the limit it hit in `limit`:
`{"name": "runs", "scope": "tenant", "max": 600, "windowSeconds": 60}`. The SDKs
wait out `Retry-After` and retry. `GET /v1/billing` has the account's run limit
(`runsPerMinute: {limit, afterPurchase?}`), and the console's Billing page shows it.

| Limit (`limit.name`) | Scope | Value |
| --- | --- | --- |
| `api_requests`: requests to `/v1/*` | client address | 600 a minute |
| `auth_requests`: requests to `/console/auth/*` and `/oauth/*` (sign-in, sign-up callbacks, OAuth) | client address | 20 a minute |
| `signups`: new accounts | client address | 5 a UTC day; past it, sign-in says so instead of making the account |
| `password_failures`: failed email and password sign-ins (an unknown address counts as a wrong password) | email address, and client address | 10 per 15 minutes per address; 20 per 15 minutes per client address. Past either, sign-in answers 429, even with the right password, until the window turns over |
| `email_requests`: requests that mail a link (email sign-up, password reset, adding a password), where the runtime has account mail | client address | 10 an hour |
| `emails`: those mails to one address, whether or not it has an account | email address | 5 a UTC day |
| `agent_creates`: `POST /v1/agents` (an upsert that changes its agent too) and forks (`POST /v1/agents/:id/fork`) | account | 600 a minute, against abuse only: making agents costs almost nothing. Design around [busy agents](#usage-tiers) instead |
| `runs`: runs started (prompt, continue, execute), however sent: REST, SDKs, MCP, schedules, channels | account | 600 a minute; 240 on free credit (the 429 says buying credit raises it) |

- A client address is the caller's IP address; an IPv6 address counts with the
  rest of its `/64`. The runtime's own calls (hosted MCP tools calling the API)
  are not counted.
- `api_requests` refills continuously (a request comes back every tenth of a
  second at 600 a minute); the others count in fixed windows (the minute, 15
  minutes, the hour, or the UTC day), so `Retry-After` is the time to the next window.
- A retried request (the same request id or `Idempotency-Key`) that the runtime
  answers from its record is not a new run.
- An upsert whose configuration equals the agent's (the same `configHash`) is
  not an agent create: deploying 50 unchanged agents counts nothing. A fork
  counts, `atMessage: 0` included: it makes an agent (and a copy of its
  workspace). For a run without the history, send `history: "none"` instead.
- **Headers.** Answers that count against `agent_creates` (creates, upserts,
  forks) or `runs` (`POST /v1/agents/{id}/prompt`, and the SDKs' requests)
  carry `X-RateLimit-Limit` (the account's limit a minute),
  `X-RateLimit-Remaining` (what is left of it this minute) and
  `X-RateLimit-Reset` (seconds until the window resets), and so do their 429s,
  with `Retry-After` equal to `X-RateLimit-Reset`. Windows are fixed and align
  to the clock minute (UTC), not to your first request: 60 runs at 12:00:59
  and 60 more at 12:01:00 are both allowed. The headers say only the calling
  account's own counts. An account with no limit (an admin tenant) gets none,
  and neither does a retried request. A create with a first `prompt` carries
  the create's.
- Admin tenants (the operator's own, from its tenants file) are not rate
  limited: neither their account limits, nor `api_requests` for requests made
  with their tokens, browser tokens or console sessions. An admin tenant's
  `maxAgentCreatesPerMinute` and `maxRunsPerMinute` set limits for it anyway.
- Operators set every value (see [Configuration](../operations/configuration.md)),
  and a self-serve account's own with `PUT /v1/tenants/{id}/limits`
  `{agentCreatesPerMinute, runsPerMinute}` (see [Billing](../operations/billing.md)). A self-hosted runtime has no per-address limits unless it
  sets them, or trusts Cloudflare's `CF-Connecting-IP`.
- Channel senders and Get Help have limits of their own (below, and in
  [Errors](errors.md)).

## Agents

| Limit | Value |
| --- | --- |
| An agent's key (`Idempotency-Key` on `POST /v1/agents`, the SDKs' `upsert(key)`) | 1–80 characters of `A-Z a-z 0-9 _ -` |
| Lifetime (`ttlSeconds`) | 60 s to 31,622,400 s (366 days), or `null`: until deleted. Default: until deleted for an agent made with a key; 1 day for one made without |
| Create body (`POST /v1/agents`, with `initialMessages`) | 18 MiB |
| Imported history (`initialMessages`) | 16 MB of JSON (`HISTORY_TOO_LARGE`, 413) |
| `systemPrompt`, `systemPromptAppend` | 32,000 characters each |
| `modelHeaders` | at most 20 headers, 8 KB in all; never auth headers |
| `spendLimit.usd` | 0 to 1,000,000 |
| `subject` | a string; `context`: at most 4 KB |
| Mounts | at most 16 per agent |
| Agents busy at once per account | by [usage tier](#usage-tiers), across the whole runtime (not per node). An agent is busy while it has a run open, running or queued; a busy agent queues more runs without another slot. A run past the limit gets 429 `BUSY_AGENT_LIMIT` (below) |
| Tools in an agent's catalog | 4,096 tools, 16 MiB of schemas; at most 64 declared directly to the model (the rest are reached from js_exec) |

### Usage tiers

An account's tier comes from what it has paid for credit in total, net of refunds.
Starting credit and other grants do not count. A payment moves the account up as soon as it lands.

| Tier | Paid in total | Agents busy at once |
| --- | --- | --- |
| Free | nothing yet | 20 |
| Tier 1 | $5 | 50 |
| Tier 2 | $50 | 100 |
| Tier 3 | $250 | 250 |
| Tier 4 | $1,000 | 1,000 |

`GET /v1/billing` has `busyAgents`: the limit, how many are busy now, the tier, and the next one
(`next: {tier, paid, limit}`); the console's Billing page shows the same. An account whose limit
the operator set (the tenants file's `maxAgents`, or `maxBusyAgents` with
`PUT /v1/tenants/{id}/limits`) has `source: "tenant"` and no tier. Self-hosted runtimes set the tiers with
`AGENT_USAGE_TIERS` ([configuration](../operations/configuration.md)).

At the limit, a run (a prompt, `continue` or `execute`) gets 429 with `Retry-After`:

```json
{
  "error": "This account has 20 agents busy, the most its usage tier (Free) allows; retry when one finishes. $5 more of credit unlocks Tier 1: 50 busy agents (it applies once the account has paid $5 in total).",
  "code": "BUSY_AGENT_LIMIT",
  "busyAgents": { "busy": 20, "limit": 20, "source": "tier", "tier": "Free", "paid": 0, "next": { "tier": "Tier 1", "paid": 5000000, "limit": 25 } }
}
```

Amounts are micro-USD. The SDKs retry it after `Retry-After`, like any 429. Creating agents,
reading them and sending them input do not count; only runs do.

## Runs and requests

| Limit | Value |
| --- | --- |
| Request id (a prompt's `requestId`, the SDKs' `idempotencyKey`) | 1–80 characters of `A-Z a-z 0-9 _ -` |
| Settled requests kept per agent for idempotent retries | the most recent 256 |
| Open requests per agent (running and queued) | 32; more is 429 `Too many requests queued for this agent` |
| Prompt body (`POST /v1/agents/:id/prompt`) | 6 MiB, with inline files |
| Request body over an agent's own token (`/clients/:id/requests`, `/mcp`) | 1.1 MB (1,100,000 bytes) |
| `text` | must not be blank, unless the message attaches audio ([Voice and audio](../guides/voice.md)) |
| `from` | `id` 1–200 characters; `name`, `username` at most 200 each |
| `metadata` | at most 16 keys of 1–64 characters, string values of at most 512 characters |
| `configure` body | 1 MiB |
| Provider retries within a turn | 3 attempts, backing off from 2 s (overload, rate limits, 5xx, dropped streams); context overflow is not retried |
| Model responses in one run | 1,000, compaction summaries included; `runLimits.maxResponses` lowers it for an agent or a definition, and the operator sets the maximum (`AGENT_MAX_RUN_RESPONSES`, or per tenant `maxRunResponses`; admin tenants have none unless their entry sets one). At it, the turn stops before its next model request: `stopped: "turn_limit"` |
| A run's time | 2 hours from when it began, checked before each model request; `runLimits.maxSeconds` lowers it, the operator sets the maximum (`AGENT_MAX_RUN_SECONDS`, or per tenant `maxRunSeconds`; none for admin tenants unless set). `stopped: "turn_limit"` too; send another message to continue. A turn still inside one model request or tool call 60 s past its limit is aborted there, and its agent stopped at 120 s |
| A quiet model stream | a model request that sends nothing before its first token (text, thinking or a tool call) for 120 s (300 s for a reasoning model at `thinkingLevel` high and up), or nothing for 45 s once it streams, is ended as stalled and retried like other transient failures; keep-alives do not count. `runLimits.firstTokenSeconds` and `runLimits.idleSeconds` set an agent's or definition's own (1 to 3,600); the operator sets the runtime's (`AGENT_MODEL_FIRST_TOKEN_SECONDS`, `AGENT_MODEL_IDLE_SECONDS`). Past every retry the run fails with code `model_stream_stalled` |
| Wait | none beyond a run's time limit; a turn waiting on people (`input_required`) is not running, and may wait for days. The SDKs have no default timeout |
| `Idempotency-Key` header (any other POST) | 1–255 characters; its answer is kept for 24 hours |
| Stateless run (`POST /v1/runs`) body | 7 MiB, with inline files (4 MiB of files in all) |
| A stateless run's `wait` | at most 60 seconds on create, 25 on `GET /v1/runs/{id}`; it then answers with the run still running |
| A stateless run's retention | its result, events and messages are kept for a day after it ends (`retentionSeconds`: 60 to 604800; the operator's default is `AGENT_RUN_RETENTION_SECONDS`), then deleted. Its `Idempotency-Key` names it for as long. A run whose end was never recorded (its node died at that moment) is deleted 7 days after its retention would have begun |
| Stateless runs and limits | each counts against runs per minute and busy agents, as an agent's run does; not against agent creates or the agents a tenant has |

## Files

| Limit | Value |
| --- | --- |
| Files attached to one message | 20 |
| Inline (base64) file bytes in one message | 4 MiB in all, decoded; upload larger ones first (`PUT …/uploads/:requestId/:name`) and attach them by path |
| A file attached by URL (`{url}`) | 64 MiB, fetched within 60 s, at most 3 redirects, public addresses only |
| One file (upload, volume write) | 256 MiB |
| An upload's whole request | 15 minutes (other requests: 30 s without progress in the SDKs) |
| Image the model sees natively | 5 MiB and 8,000 pixels a side (larger ones are described in text); sent at most 1,568 pixels a side, scaled down in the request |
| PDF the model sees natively | 16 MiB and 100 pages |
| Files in one model request | 24 MiB and 100 images; older files past that are described in text |
| Parsing an untrusted file for its text | 32 MiB in, 10 s, 1,000,000 characters out |
| Files a run lists in its outcome | 100 written (`files`), 20 presented (`presented`) |
| Signed links (`POST …/links`) | `expiresIn` 1 to 86,400 s, default 900 |
| A volume | 100,000 files, 100 snapshots and 10,000 pinned ones; the change feed keeps the last 1,000 changes; a listing page is at most 1,000 files |
| Channel attachments | 10 files a message, 25 MiB each, 100 MiB in all |
| Storage per tenant | 1 GB (10^9 bytes) on free credit, 100 GB once it has bought credit; an operator can set another per tenant. Counted as the storage charge counts it: file contents (each distinct content once), agents' history logs and volumes' file trees. A write that would pass it is refused with 507 `STORAGE_LIMIT`, its body carrying `limit` and `used` in bytes: delete files or volumes to make room. Uploads, file writes and tool outputs all count |
| Storing on spent credit | a prepaid tenant at a zero balance cannot store more: uploads, file writes and tool outputs get 402 `INSUFFICIENT_CREDIT`. Reading and deleting still work |


## Audio

See [Voice and audio](../guides/voice.md).

| Limit | Value |
| --- | --- |
| One audio file transcribed | 25 MB and 30 minutes, its length read from its container before it is sent (413 `AUDIO_TOO_LARGE`, `AUDIO_TOO_LONG`) |
| Audio transcribed for one message | 5 files, 30 minutes in all |
| Formats | Ogg (Opus, Vorbis), WebM, MP3, M4A/MP4, WAV, FLAC; others, and audio whose container gives no length, are 415 `UNSUPPORTED_AUDIO` |
| `POST /v1/transcriptions` body | 25 MB of audio (multipart), or its base64 in JSON; each counts as a run against runs per minute |
| A provider's answer | 5 minutes |

## Images

See [Images](../guides/images.md).

| Limit | Value |
| --- | --- |
| Prompt | 32,000 characters |
| Images to edit | 4 per request, PNG, JPEG or WebP, 25 MB each and 50 MB in all, at most 8,000 pixels a side (413 `IMAGE_TOO_LARGE`; other types 415 `UNSUPPORTED_IMAGE`) |
| Images made | 4 per request (`n`) |
| Sizes and qualities | `1024x1024`, `1536x1024`, `1024x1536`; `low`, `medium`, `high` |
| `POST /v1/images` | each request counts as a run against runs per minute |
| A provider's answer | 3 minutes |

## Tools

| Limit | Value |
| --- | --- |
| A tool result the model reads | 32,000 characters; a longer one is saved whole (up to 700 KB) to `/workspace/tool-results/<toolCallId>.txt` |
| Attached tool call deadline (tools in your process) | 15 s without an answer by default; a tool's own `timeoutMs` from 1 s to 20 minutes |
| Remote MCP server call deadline | the source's `timeoutMs` (1 s to 20 minutes), default 60 s |
| OpenAPI operation deadline | the source's `timeoutMs` (1 s to 20 minutes), default 30 s |
| Progress | each progress notification restarts a call's deadline, up to 20 minutes in all. Progress events are published at most every 250 ms per call |
| One MCP result from the SDKs (a tool's return value) | 1 MiB of JSON |
| A remote MCP server's response | 8 MiB |
| An OpenAPI spec | 8 MiB; at most 1,024 operations allowed (`allowTools`) |
| Tool sources per definition | 64 MCP servers, 64 OpenAPI specs; `allowTools`/`denyTools` at most 512 names (MCP) |
| A file in a tool's arguments (base64, or inline as `data:`) | 4 MiB |
| A file's URL in a tool's arguments | 5 minutes, bound to the call and the file's version |
| A directory in a tool's arguments | 1,000 files, 256 MiB |
| A binary tool response saved to the workspace | 64 MiB; 64 MiB per call and 256 MiB per run saved in all |
| An MCP text resource shown inline | 64 KiB (longer ones are saved as files) |

### js_exec (code the model writes) and `execute`

| Limit | Value |
| --- | --- |
| Wall time | 30 s by default, at most 60 s (`timeoutMs`; a longer one is cut to it). Admin tenants may ask for 120 s; an operator can set a tenant's maximum up to 120 s (`codeMaxTimeoutMs`) |
| CPU time | 2 s of keeping its thread busy, TypeScript stripping included (time waiting on tools does not count). Enforced from outside the guest: an execution past it is stopped whatever it is doing, with `Codemode CPU limit exceeded`. An operator can set a tenant's up to 30 s (`codeCpuMs`) |
| Executions at once | 4 per tenant on each node (2 on free credit; `codeConcurrency`), all such tenants together within what the node's memory affords (6 on a 2 GB node). Executions past it wait their turn, tenants in rotation, within their own `timeoutMs`. Admin tenants are not limited unless their entry sets it |
| Memory | a 128 MiB V8 heap (reaching it ends the execution) and 128 MiB of ArrayBuffers (past it, a `RangeError`) |
| Output | 32,000 characters by default, at most 128,000 (`maxOutputCharacters`); 1,024 chunks |
| Tool calls | 256 per script, at most 32 in flight |
| Tool traffic | arguments at most 128 KiB of JSON a call, results at most 1 MiB, 8 MiB in all |
| One `fs.readFile` / `fs.writeFile` | 700 KiB |

## People

| Limit | Value |
| --- | --- |
| How long an input waits | 7 days by default; a definition's `humanInput.expiresInSeconds` from 60 s to 30 days, never past the agent's expiry |
| Inputs one tool call may ask at once | 8 |
| An input's message, an approval's shown arguments | 4,000 characters |
| Answers in one batch (`POST …/inputs`) | 1–100; one answer's body 256 KiB |
| Approvers (`humanInput.approvers`) | 100 |
| `ask_user` | 1–4 questions, each with 2–4 options and a header of at most 12 characters |

## Sub-agents

See [Multi-agent](../guides/multi-agent.md).

| Limit | Value |
| --- | --- |
| Delegation depth (`delegate.maxDepth`) | 2 by default (a parent, its children and theirs); 1–5 |
| `delegate` calls in flight per run (`delegate.maxParallel`) | 4 by default, 1–16; more wait their turn |
| A sub-agent's spend | what its parent's run and agent spend limits have left when it starts, as its run's spend limit; what it spent counts against both |
| A sub-agent's lifetime | a day (86,400 s), as a scratch agent's; one named by key (`{ agent }`) is yours and keeps its own |
| A `delegate` task | 100,000 characters; inline `instructions` 32,000 |
| Agents in one allowlist (`delegate.agents`) | 32; a name 1–64 letters, digits, `_` and `-`; a description at most 1,000 characters |

Sub-agents are agents: each counts against busy agents, the run rate and your
spend limits like any other.

## Streams and browsers

| Limit | Value |
| --- | --- |
| One SSE frame | 1.1 MB; a larger event is sent as `event_omitted` |
| Events buffered per agent for replay | the last 512, at most 2 MiB; a cursor behind them gets a snapshot (or `REPLAY_GAP`) |
| A snapshot's messages | about 1 MB; more is `truncated: true` (read history) |
| Long poll `wait` | at most 25 s |
| Read-only subscribers (watchers and waiting polls) | 32 per agent, 1,024 per tenant on a node (or the tenant's `maxWatchers`), 4,096 per node; past it, 429 |
| Browser token lifetime | 5 to 3,600 s, default 900; its stream ends when it expires |
| Browser token `events` list | 64 types |
| History page (`?limit=`) | 1 to 500 messages, default 50 |

## Schedules, channels and webhooks

| Limit | Value |
| --- | --- |
| Schedules per agent | 100 |
| Repeating schedules | `everySeconds` at least 60 |
| Schedule delivery retries | 3, after 1, 5 and 15 minutes (none for a 402 or another refusal a retry cannot change, nor past the next occurrence); then that occurrence is skipped and recorded (`failures`, `lastError`) |
| Schedule body | 64 KiB |
| Channel senders | `perSenderPerMinute` 1–600 (default 10), `turnsPerDay` 1–1,000,000 (default 1,000); `allow` at most 1,000 senders |
| Channel daily turns | count messages and, since they also post, turns started through the API or a schedule; past the limit those do not post |
| Camel Discord servers per account | 10, or 1 on free credit (an operator can change either) |
| A Camel Discord server | `perSenderPerMinute` 1–100 (default 5), `turnsPerDay` 1–10,000 (default 100; at most 500 on free credit); no `schedule` builtin |
| Webhook endpoints per tenant | 16 |
| A webhook delivery | 10 s to answer; retried until delivered, for up to 3 days |
| A rotated webhook secret | keeps signing beside the new one for 24 hours |

## Trace export

| Limit | Value |
| --- | --- |
| Endpoints per tenant | 1 (`PUT /v1/telemetry`), OTLP/HTTP only (protobuf or JSON) |
| Headers | 16, each value at most 4,096 characters; endpoint at most 2,048 |
| Spans waiting to be sent | 5,000 per tenant and 20,000 in all, per node; more are dropped |
| An export request | at most 512 spans; 10 s to answer; 5 attempts, retrying 429, 502, 503, 504 and connection failures |
| A content attribute (with `include.content`) | 16,384 characters, then cut |

## Spending

| Limit | Value |
| --- | --- |
| An agent's spend limit | from when it is set: new prompts are refused, and a running turn stops after the response that crossed it (`stopped: "spend_limit"`) |
| Run limits | 1,000 model responses and 2 hours a run (see [Runs and requests](#runs-and-requests)): `stopped: "turn_limit"` |
| A tenant's monthly cap (`maxMonthlyCost`) | 402 for new runs once reached |
| Prepaid credit | 402 at a zero balance, for runs and for storing files; free credit allows $1 of usage per hour (429 past it) |
