Cap what an AI agent can spend before it spends it
Refused before egress, priced against everything the route could reach, never estimated at zero. The head of IT explaining a four-figure line that arrived six weeks late A retry loop or a promoted model turns an ordinary week into an invoice nobody budgeted for. You find out from the vendor, and the control everybody assumed was on turns out to have been a chart.
A dashboard tells you what you spent after you spent it.
The control a finance owner is asking for is the one that refuses the call, and that means holding a defensible price before it leaves the building. That is a harder problem than drawing the chart, which is why most of the market stops at the chart. A token quota is no substitute: it bounds volume, and volume and money diverge exactly when it matters.
4 steps, in this order.
Give each agent a record
Ceilings bind a governed subject, so every agent needs a registry row and a named owner. The gateway resolves it per call, so an edit applies without a redeploy.
Populate the price table
The 50 shipped rows load additively at boot. Check every model your agents can reach has one, fallbacks included.
Set the ceilings that match the failure
Per request catches one absurd call, hourly a retry loop, daily and monthly the drift. Day and month start at 00:00 UTC.
Decide what happens when it bites
A refusal is a 429 with a typed reason and a recorded blocked trace, and nothing partially executes.
See how budgets are checked against every reachable fallback.
See how a ceiling is enforcedBuilt for
- Agents you can point at a new base URL, whose model traffic arrives at the gateway first.
- A price table you have checked covers every model those agents can reach, fallbacks included.
- Anyone who would rather a call was refused than reported, and can accept the availability trade.
Wrong for
- Anyone who wants a ceiling on Copilot, ChatGPT or Cursor seats. A seat is priced per seat, so a per-request ceiling is inert.
- Anyone who needs retry and failover underneath a hard ceiling. A call under one gets one potentially billable attempt.
- Anyone who wants a team-level or fleet-level budget pool. Ceilings bind one governed subject at a time.
One thing on the record
The shipped price rows once loaded only under the demo seeder, which the documentation tells production operators not to run, so the documented install started empty, and every per-request ceiling admitted every request while the console displayed it.
Rows now load additively at boot, and a budgeted agent whose route reaches an unpriced model is refused with a 409 before egress.
Where this is publishedThe money verdict is taken last, and priced against everything reachable.
USD is skipped in the first pass for any agent with a ceiling, because money cannot be decided until routing has fixed which upstream will serve the call. The primary target and every fallback are then priced against the resolved model rather than the name the caller typed; otherwise a rerouted target is a zero-dollar escape hatch.
- perRequestUsd
- Refuses one call whose conservative estimate exceeds the ceiling. Inert on a subscription seat, which prices the seat rather than the request.
- hourlyUsd, dailyUsd, monthlyUsd
- A rolling sixty minutes, the UTC day and month. Each blocks when the window is at the limit and when the projection would cross it.
- The unpriced refusal
- A 409 before egress naming the model, the provider that would have served it, and how many fallbacks are also unpriced.
- Long cache writes
- Anthropic and Bedrock bill a five-minute cache write at 1.25 times input and an hour at 2 times. Any other TTL prices at twice input.
Every check lives in one function, so you can read your rules and know what they do.
POST /v1/chat/completions
The key resolves to one registered agent with a named owner, and the trace is opened before anything can refuse the request.
Kill switches, then lifecycle, then deny-by-default permissions across every delegation hop, then rate limits, then your policies by priority.
returns: allow · block · require_approval — plus a redaction plan
A spend ceiling is the deliberate exception: it is deferred until routing has fixed which provider and model will serve the call, so it is tested against the price you will pay.
Routed to the provider you configured, on your key. Metering runs last and the trace closes with a terminal status.
The plan is applied to the outbound payload and a redaction event records kinds and counts, never values. A redaction that cannot be applied faithfully becomes a refusal instead.
An approval bound to a hash of this exact payload, single-use and expiring. The caller receives the approval id and the header to resume with.
429 ACP_BUDGET_EXCEEDED or ACP_RATE_LIMITED where a ceiling decided it. The trace closes as blocked and is kept as thoroughly as one that went through.
Verdict names and status codes are the product’s own. Every rule can run in shadow mode first, where the decision is recorded and the request is not changed. That is how you learn your false-positive rate before you refuse real work.
A parked request holds its money until the decision ends.
Forget the estimate while somebody deliberates and an agent queues a thousand expensive calls past its ceiling; hold it forever and a denied approval counts against that budget until someone edits the database by hand. So the reservation lasts exactly as long as the decision, and every terminal path releases it in the same transaction as the state change that ended the wait.
4 things this still does not solve.
- There is no team-level or fleet-level budget pool. A team figure is the sum of the per-agent ceilings that exist, beside a count of the agents that have none.
- Nothing is reconciled against a vendor invoice. Every figure is metered against price rows you hold, and a shipped row is a list price captured on a date that will go stale.
- A hard ceiling costs you retry and failover, because a timeout cannot prove the vendor did not complete and bill the call.
- Token Observe cannot bound spend it never sees. A vendor credential used directly is a discovery problem before it is a budget one.
Check the product limits alongside the job you want to do.
What we do not claimThe parts that do the work.
Spend controls
Hard USD ceilings, per-minute rate limits and a kill switch, all decided before the request leaves your network.
One billable egress: no retry, no failover
Model routing
Six upstreams behind one set of policies, and a fallback chain that will not launder a refusal.
Nothing verifies a provider's ZDR or training claim
Policy engine
One deterministic verdict on every governed request: allow, block, redact, or park it for a human.
Injection scoring is nine fixed patterns, not a model
Questions
What happens when an agent hits its monthly ceiling mid-conversation?
The next call is refused before it reaches a provider, with a 429 naming the limit type, the configured value and the actual figure. Nothing partially executes and nothing is billed, and the attempt is still recorded as a blocked trace. A budget warning is published at 80 per cent of any window and a budget-exceeded event at 100 per cent.
Can two concurrent requests both slip past the same cap?
No. The USD admission runs inside one per-agent transaction that reads the windows, tests the projection and writes the reservation before releasing the lock, and in-flight requests count: a running trace contributes the greater of its billed cost and its reservation.
What happens if a model has no price row?
For an agent with any USD ceiling, the request is refused with a 409 before egress, naming the unpriced model and how many fallbacks are also unpriced. The alternative was tried and was worse: an unpriced model produced a zero estimate, which silently disarmed every per-request ceiling.
Describe the version of this you have.
Say what your estate contains and which part of it worries you, and the reply will say where to start.