# Rate limits & budgets

> RateLimit headers, 429 semantics, and per-key spend ceilings


## Request rate

/v1 requests are limited per caller (per API key). Every response carries:

```text
RateLimit-Limit: 120
RateLimit-Remaining: 87
RateLimit-Reset: 17
```

Hitting the limit returns `429 rate_limited` (retriable) with `Retry-After`.
Polling a run every 15s uses ~4 requests/minute — the limit exists to stop
runaway loops, not normal integrations.

## Model-call limits on the free surfaces (abuse guard)

Some endpoints make a model call that is **not** a paid run: the intake and
guidance parsers, run preflight, Blueprint onboarding infer/adjust, and report
chat. These are metered per caller separately from the request rate above, so a
stuck loop cannot burn tokens on work nobody is paying for:

| surface | per minute | per day | on refusal |
|---|---|---|---|
| parsers, preflight, onboarding, chat | 30 | 500 (shared) | `429 rate_limited` / `429 llm_daily_limit_exceeded` |
| `POST /v1/research/runs` and `/estimate` with a `query` | **120** (matches the request limit) | 500 (shared) | `429 rate_limited` |

Founders and Enterprise plans get 3× these figures. `llm_daily_limit_exceeded`
is a **rate limit, not a billing wall** — topping up does not lift it; retry
after the rolling 24h window or ask support to raise it. Sending `seeds` instead
of `query` skips the parse and is not subject to this table.

**Auto-suspend.** A key that keeps hitting refusals — 20 blocked calls, or 5
`unparseable` / off-purpose verdicts, within 10 minutes — is paused:
`403 key_suspended`, an audit entry, and an email to the org owner. Two paused
keys in 24h pause the owning user (`403 account_suspended`; `suspended` on
`/v1/me` says so up front). **Stop and alert a human; do not mint a new key** —
a fresh key of a paused user is refused the same way. The `query` parse on run
create/estimate is the one exception to the blocked-call count: a successful
parse is charged as a run, so being *fast* there never pauses a key — only
repeated `unparseable` verdicts do.

## Run concurrency & credits

Separate from request rates, run creation can return:

- `429 run_concurrency_exceeded` — your ORG's run caps, set by your own admin
  (`/api/billing/limits`). Queue and retry.
- `402 insufficient_credits` — prepaid balance too low; a human must top up.
- `402 plan_upgrade_required` — the plan does not include this capability (e.g.
  Max-depth runs, webhooks, the audit log). **Topping up will not help**; a human
  must upgrade. Never retry this one.
- `402 budget_exceeded` — this key's own `budget_runs`/`budget_cents` ceiling (set in the create-key dialog or via `POST /v1/keys`).

The three codes are distinct because the correct agent response differs:
back off / queue / **stop and alert a human**.
