Budgets
An agent is quoted before it spends and refused when it would breach. Four ceilings, integer micro-USD, and a refusal the agent can read while it is still running.
After this page you can cap what an agent spends, read what it has spent, and tell a budget refusal from a model failure.
What a budget is
Every model call and every priced tool call an agent makes is quoted before it is made — an upper bound on what the call could cost — and that quote is checked, in this order, against four things:
- your organization's balance — can it be paid for at all
- the agent's period cap —
cap_micro_usd, less what this period spent - the task ceiling —
max_task_micro_usd, less what this run spent - the session's budget —
budget_micro_usd, less what this session spent
Any one of them refuses the call. There is no flag and no bypass: a run reaches a model only through the gate.
Money is integer micro-USD
Every amount is an integer number of micro-USD, in a field suffixed
_micro_usd. 1,000,000 is one dollar, so 11902000 is $11.902 and 250 is
a fortieth of a cent. A call costs fractions of a cent; a cap kept in cents
could not see one.
Stating a budget
All three fields are required when you define an agent.
curl -X POST https://api.hanzo.ai/v1/agent \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "triage",
"model": "zen5",
"instructions": "Triage inbound issues.",
"cap_micro_usd": 20000000,
"max_task_micro_usd": 500000,
"period": "month"
}'That agent may spend 0.50.
cap_micro_usdmust be positive. A cap of zero would mean no limit and no record, which is the state a budget exists to remove.max_task_micro_usdmust be positive and cannot exceed the cap.periodisday,weekormonth.
Periods are calendar-aligned in UTC: month means the month, not thirty
days from the first call, and week starts on Monday. The window rolls on the
first call after it turns over, and consumed_micro_usd goes back to zero.
Reading what it spent
GET /v1/agent/{ref}/spend{
"cap_micro_usd": 20000000,
"max_task_micro_usd": 500000,
"period": "month",
"consumed_micro_usd": 11902000,
"remaining_micro_usd": 8098000,
"by_component": { "model": 11431000, "computer": 402000, "tool": 69000 }
}by_component splits the spend three ways: model is every completion the
agent bought, computer is the runtime it was resident for, tool is a
priced tool call. A component with no spend is absent, not zero.
What a refusal looks like
A breach answers 402 with the code budget_exceeded:
{
"error": {
"code": "budget_exceeded",
"message": "task budget exceeded: this call would cost up to 620000 micro-USD and 118000 remain",
"event": "budget.exceeded",
"scope": "task",
"component": "model",
"quote_micro_usd": 620000,
"remaining_micro_usd": 118000
}
}scope names which ceiling refused — agent, task or session — so you know
whether to raise the month, the run or this one session.
The agent is told in band. Under a session the same payload is appended to
the session's event stream as a status event from budget, so an agent reads
its own refusal while it is still running and can wrap up — write what it has,
say why it stopped — rather than crash on a failed call.
budget_exceeded is not a model failure. A call the model failed is retried; a
call the budget refused is not, because retrying it would refuse it again.
Quotes are upper bounds, settlement is actual
The quote errs large on purpose: the prompt as it will be sent, plus the largest
completion the request allows — max_tokens, or 4,096 when the request names
none — at the platform's inference rate.
When the call has happened, what the gateway actually reported is settled against every tally the quote was checked against, and the difference comes back to the cap. A call that failed never settles, so it is never billed and its headroom returns.
This is why an agent can be refused with headroom that looks sufficient: the gate compares the ceiling of the next call, not its likely cost.
A session's own budget
A session may carry a ceiling of its own, under the agent's:
curl -X POST https://api.hanzo.ai/v1/agent/sessions/$ID/budget \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"budget_micro_usd": 2000000}'A session that reaches its own budget is paused, not failed — work resumes the moment you raise the cap or remove it. Three rules:
- a replacement must be strictly greater than what the session has consumed
- removal is one-way:
{"budget_micro_usd": null}takes the cap off for good, and that session cannot be given one again - a session created without a budget cannot be given one later
Each of those refuses with 409 rather than quietly doing something else.
An agent defined before budgets existed
It carries a cap of zero and is not capped — its spend is still tallied and
readable at /spend, and an update gives it a cap. Refusing every agent defined
before the feature shipped would be an outage, not a policy.
Next
- Agents — the definition a budget hangs on.
- Agents reference — every operation, generated.
- Pricing — what the platform charges, and what the fee on a model call is.
How is this guide?
Last updated on