Sign in

Products

Breaker

A budget one run carries, declared in request headers. The run is refused at its own line and stays stopped; other runs keep going.

On this page

Recovea Breaker is a budget one run carries, in dollars. When the run reaches it the next request is refused, and the run stays stopped until a person starts a new one.

What a run is

Whatever your own system already treats as one piece of work: an agent task, a chain, a nightly job, one thread. Set the run id to your trace or thread id. The envelope is the dollar figure that run may spend. Run envelopes are on every plan, Free included.

Only the calls that name a run in a header carry a Breaker. A call that names none is untouched by it, and is still bound by the caps on your organization and key.

What the request carries

Three request headers, declared by the run itself:

Header What it takes
x-recovea-run-id 1 to 128 visible ASCII characters. A run header sent without it is refused rather than dropped.
x-recovea-run-budget Decimal US dollars, 6 decimal places at most. A run may declare up to twenty-five dollars without approval.
x-recovea-run-ttl Whole seconds. 3600 by default, 60 at the shortest, 86400 at the longest.
Declare a run
curl -sS -D - https://api.recovea.ai/v1/chat/completions \
  -H "Authorization: Bearer $RECOVEA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-recovea-run-id: nightly-summary-2026-09-02" \
  -H "x-recovea-run-budget: 0.50" \
  -H "x-recovea-run-ttl: 900" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"ping"}]}'

Nothing is configured first. The first request that names a run opens its envelope, and every request that names the same run id spends from it.

A malformed run header is a syntax error, and the request never reaches your provider: it answers 400 with error.type invalid_request_error and error.code invalid_run_id, invalid_run_budget or invalid_run_ttl. Run headers are control, so a bad one is refused rather than dropped: a caller whose budget was silently dropped would believe the run was bounded while it ran with no envelope at all.

What the gateway does

It keeps a counter per run and checks it at admission, before your provider is contacted, exactly as it checks a cap. An envelope only ever tightens: it nests inside the caps on your organization and your key and can never raise them.

A run that declares more than it may declare on its own is not refused. Its envelope is lowered to the most it may declare, and the response says so.

The x-recovea-* run headers are removed before the request is forwarded, so they never reach your provider.

What comes back

Served

Every answer on a run carries the envelope that actually binds, to six decimal places:

HTTP
x-recovea-run-budget-effective: 0.500000

Declare more than a key may declare on its own and the figure is lowered rather than refused, with x-recovea-run-clamp-reason: policy_max beside it saying which bound cut it. When nothing cut the declaration, no clamp reason is sent.

Refused at the run's line

Every Recovea limit answers in one shape — one status, one type, one code — and the sentence inside it names the window that reached its line. A run budget says run.

A run over its envelope
HTTP/1.1 402 Payment Required

{
  "error": {
    "message": "Run budget reached. This run is stopped for good; start a new run to continue.",
    "type": "insufficient_quota",
    "param": null,
    "code": "budget_exceeded"
  }
}

The refusal carries x-recovea-budget-scope: run and x-recovea-budget-window: run. The body does not name the run. Your own run id names it on the request, and the refusal is receipted against the run itself.

Three codes reach a run:

Status error.code What it means
402 budget_exceeded The run reached its envelope and was stopped mid-run, before the provider was called.
402 run_expired The run's time-to-live ran out and the policy is armed death, so later requests were refused. THIS WAS NOT AN OVERSPEND.
503 budget_unverifiable An armed limit could not verify live spend, so it refused rather than let spend run unwatched. THIS WAS NOT AN OVERSPEND.

The meanings are the platform's own sentences, printed the same way here. Both 402s carry error.type insufficient_quota. run_expired reads no figure, so it carries no budget headers. budget_unverifiable carries Retry-After: 1 and clears on its own; retry it, as the quickstart shows.

A tripped run stays tripped

A tripped run does not re-arm. Declaring a bigger budget under the same run id is refused the same way; only a new run id opens a new envelope. A sibling run on the same key keeps its own envelope and keeps going.

An envelope is evaluated between requests, so a response already streaming when the line was reached can overshoot it by roughly one reconcile interval.

In the platform

The Runs page lists your runs, each with its key and its state, and a run's own page records the refusals and requests made under it, with the figures as they stood when they were recorded. The most a run may declare without approval is the Self-declare threshold on the run policy page, which an Owner or an Admin can change (Roles).