Docs

One run. One budget.

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.

The three headers

x-recovea-run-id1 to 128 visible ASCII characters. A run header sent without it is refused rather than dropped.
x-recovea-run-budgetDecimal US dollars, 6 decimal places at most. Declare up to $25.00 without approval.
x-recovea-run-ttlWhole seconds. 3600 by default, 60 at the shortest, 86400 at the longest.
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"}]}'

What comes back

Every answer carries x-recovea-run-budget-effective: the envelope that actually binds. 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.

An envelope only ever tightens. It nests inside the limits above it — workspace, then key, then run — and can never raise them.

What a refusal says

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. 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.

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"
  }
}

Three codes reach a run, all of them insufficient_quota:

budget_exceededThe run reached its envelope and was stopped mid-run, before the provider was called.
run_expiredThe run's time-to-live ran out and the policy is armed death, so later requests were refused. THIS WAS NOT AN OVERSPEND.
budget_unverifiableAn armed limit could not verify live spend, so it refused rather than let spend run unwatched. THIS WAS NOT AN OVERSPEND.

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.

Ceilings above the run, and what an armed one answers, are on the 402 contract.