Sign in

Products

Cap

An armed cap refuses the request before your provider is called and answers 402. The body names the window that was reached.

On this page

Cap is a dollar limit on your spend that the gateway enforces in the request path. An armed cap refuses the request before it reaches your provider and answers 402. An alert only warns; a cap refuses.

What a cap is

A cap is an amount on a scope over a window:

  • the scope is your whole organization, or one API key;
  • the window is a day, a week, a month, a year, or the lifetime of the cap, on UTC boundaries (Caps and windows);
  • armed means its hard stop is on. A cap with the hard stop off counts spend and sends its alerts, and refuses nothing.

Caps are set in the platform, on Settings → Organization → Limits, and a key's cap also on that key's own row (Where a cap is set). The guide sets one up end to end.

What the request carries

Nothing. A cap is armed in the platform and pushed to every gateway node; the request carries only your key. The same request is served one minute and refused the next because the cap's counter moved, not because the request changed.

What the gateway does

Before your provider is contacted, the gateway runs admission in order: it authenticates the key, applies throttling, then checks every armed cap that covers the request, the organization's and the key's. For each cap it adds the least this request could cost to the spend already counted in the cap's current window, and refuses if the total reaches the cap. Where several caps cover a request, on one scope or on several, the tightest decides.

A refused request is never forwarded. There is no provider call, no token and no cost for it.

What comes back

Served

Your provider's response, with the kind and the window of the tightest armed cap the request was bound by:

HTTP
x-recovea-request-id: req_0192f3a4b5c6d7e8f9a0b1c2d3e4f5a6
x-recovea-budget-scope: organization
x-recovea-budget-window: month

x-recovea-budget-scope is organization or key. No figure rides a served response: what is left on a cap is in the platform, not on the wire. With no armed cap over the request, neither header is sent.

Refused at the cap

A monthly cap on the organization
HTTP/1.1 402 Payment Required

{
  "error": {
    "message": "Monthly budget reached. Traffic resumes at reset, or raise the cap.",
    "type": "insufficient_quota",
    "param": null,
    "code": "budget_exceeded"
  }
}

The refusal carries the same two headers, naming the cap that refused: x-recovea-budget-scope: organization and x-recovea-budget-window: month.

The status, error.type, error.code, the null param and the field order message, type, param, code are the contract, and they are the same for every cap and every window. Branch on them. The message is prose: it names the window that was reached, and it may be reworded.

Window The message on an organization cap
day Daily budget reached. Traffic resumes at reset, or raise the cap.
week Weekly budget reached. Traffic resumes at reset, or raise the cap.
month Monthly budget reached. Traffic resumes at reset, or raise the cap.
year Yearly budget reached. Traffic resumes at reset, or raise the cap.
lifetime Lifetime budget reached. This budget does not reset; raise the cap to continue.

A cap on one API key says so after the window: "Monthly budget reached for this API key. Traffic resumes at reset, or raise the cap." The sentence is built as the window's opening, the scope's words, then the window's closing. No refusal body names the cap, the key, the project or the run; the headers name the kind, and x-recovea-request-id is the join to your own record.

Refused in pause mode

An armed cap refuses in one of two modes, chosen on the cap form under At the cap: Block (402), the default, or Pause (429 with Retry-After). Pause answers 429 with error.type rate_limit_error, the same error.code budget_exceeded, and a Retry-After of the seconds until the window resets. Branch on the code, not the status: nothing else separates a cap's 429 from a throughput 429.

Refused because spend could not be confirmed

When an armed cap cannot confirm the spend it is counting, the request is refused with 503, Retry-After: 1 and error.code budget_unverifiable, never with the 402. The condition clears on its own. Fail-open and fail-closed has the body and the reason.

What a cap does not do

  • It stops the next request, not the ones already running. The request that crosses the line was admitted and finishes, and so do requests running at the same moment. A scope's total can end above its cap by about the cost of the requests in flight when it was reached. If you need a hard stop at a number, set the cap below it by the cost of your largest request.
  • It counts the least a request could cost, never more. The estimate added at admission is the lowest input rate on the price list applied to the size of the request, so a cap trips late rather than early.
  • It bounds routed traffic only. A provider key used directly never enters the gateway, and no cap reaches it.

Warnings and notices

Recovea does both: the warning on the way up, the refusal at the line. Threshold alerts are Team and above; a refusal mails your owners and billing contacts on any plan, Free included, once per budget each month. Alert thresholds has the percentages.

Caps work on every plan. On Free a cap's amount has a ceiling; the plans and their figures are on the pricing page.