Cap spend with a budget
A ceiling over a filtered slice of your ledger, alert-only or enforcing. What it stops, what it cannot, and how far past it you get.
On this page
A budget is a spend ceiling over a slice of your traffic for a calendar period. Define one and you get alerts as it fills. Turn on enforcement and requests in that slice stop going through once it is exhausted.
This page covers the whole mechanism: the config, the two operating modes, the three properties that decide how much to trust the number, and how a budget differs from the similarly-named governance limit.
Define one
budgets:
- id: live-model-cap
filter: request.model = "gpt-4o-mini"
period: day # day | week | month, UTC boundaries
limit_usd: 20.00
thresholds: [0.5, 0.8] # ascending fractions in (0, 1]
enforce: true # default: false — alert-only
Five fields. The filter uses the same query language as the Requests explorer, so any slice
you can select on screen you can put a ceiling on: one model, one tenant, one feature, one
agent. An empty filter means all traffic. thresholds are the fractions at which an alert
fires as burn climbs.
Periods run on UTC boundaries and reset there. A day budget resets at 00:00 UTC rather than at
midnight where you are.
You can create a budget from the Budgets surface instead. It composes the same YAML, shows it to you, and puts it through validate, diff and apply under a compare-and-set guard, so the running config and your file stay in step.
Alert-only or enforcing
enforce decides which of two things a budget is, and the surface states which one in words
rather than leaving you to infer it from a flag.
Alert-only (enforce: false, the default). Crossing a threshold fires an alert. Traffic is
untouched, and spend continues past the limit. The surface says so plainly: this does not stop
spending.
Enforcing (enforce: true). A request in the slice that arrives after the ceiling is
exhausted is turned away with a synthesized 429, and that refusal lands in the ledger as a
first-class row rather than vanishing. Refused requests are excluded from burn, so turning
traffic away cannot inflate the number that caused it.
Start alert-only. Watch a full period. Then decide whether the ceiling is in the right place before you let it stop anything.
Three properties that decide how much to trust it


Enforcement fails open. The evaluator runs off the request path. If it goes stale or dies,
enforcement suspends: traffic flows, an alert fires, and the badge reads suspended. A broken
budget will not stop your agents. That is the right trade for a gateway, and it means a budget
is a cost control rather than a safety control.
The overrun is bounded, and the bound is published. Admission reads a snapshot while burn is tallied off-path, so a breach can overshoot. The surface shows an approximate-overrun bound computed from the actual lag and drop counters rather than an adjective. Read it as the answer to “how much past the ceiling could I be”, and treat the burn figure as a lower bound.
Unpriced spend is excluded, not counted as zero. Rows the price table cannot cost do not contribute to burn, and their count is disclosed beside it. A slice full of an unpriced model will not trip a budget, which is a reason to keep the Pricing surface’s unpriced triage at zero. Override a price is how.
A budget is not a governance limit
Two mechanisms cap spend, they have similar names, and choosing the wrong one wastes an afternoon.
budgets: |
governance.limits |
|
|---|---|---|
| Scope | a filter over the ledger | a node in a tenancy tree |
| Selects by | any ledger field | the virtual key that made the request |
| Types | spend only | spend, token and request quotas, rate, concurrency |
| Hierarchy | none — budgets are flat | inherited down the tree, resolved at every level |
| Surface | Budgets | Governance |
Use a budget when the slice is a query: this model, this feature, this month. Use a governance limit when the slice is a customer or a team you have issued a key to, and you need more than dollars. Governance limits covers the second.
They coexist. A request can be inside both, and both can stop it.
Alert on a budget
A budget’s own thresholds fire alerts as it fills. You can also write a rule in the
alerts: block that watches a budget’s state:
alerts:
rules:
- id: cap-crossed
type: budget_threshold
budget_id: live-model-cap
notify: [ops-webhook]
Alert on what the ledger sees covers the rest of the rule types.
What can go wrong
The budget does not fire. Check the filter against the Requests explorer: paste the same filter text there and confirm it selects rows. A filter that matches nothing produces a budget that never burns.
Spend went past the ceiling. Expected, within the published bound, and disclosed. If it went far past, look at whether enforcement was suspended — a stale evaluator says so on the badge.
Burn looks lower than your provider bill. Compare the unpriced count. Rows with no price are excluded from burn by construction. Invoice reconciliation is the surface for that comparison.
The Budgets entry is greyed out. Budgets are defined but enforcement is not granted; the entry carries its reason. Why your sidebar is shorter covers the three navigation states.