A spend budget caps what an agent can spend, so a runaway loop can’t drain the wallet overnight. The API enforces it server-side against the receipt ledger, so the cap is a per-agent total across every process, restart, and serverless invocation that uses the wallet, not a per-instance counter. Nobody budgets for what they can’t see. So nobody budgets.
How it differs from maxCost
maxCost caps one call from one process. A budget caps the UTC day and every call, across all processes.
Use both:
maxCost is a per-call sanity check, and the budget is the overall limit.
Enforcement
Every paid route checks the budget before any payment is signed or settled:- Quote-based routes (email, voice, SMS, build, browser, commerce, compute) reject at quote time: you get the
403instead of the402quote, so nothing is signed. - Fixed-price routes reject in the payment middleware, before settlement.
- Concurrent calls are safe. On the paid leg, the check and the in-flight reservation are one atomic Redis operation, so two parallel calls can’t both fit under the cap. The reservation is released when the receipt is written. If Redis is unavailable, the guard falls back to a best-effort ledger check instead of blocking payments.
- Calls fully covered by credits don’t use budget. Failed settlements don’t count as spend.
- A capped agent stays capped during an outage: the call is held with
503 budget_unavailable(see below). An agent with no cap is not affected, and neither is a capped agent when the cache that records the cap is itself unreachable.
reason is daily or per_transaction. The SDKs raise a typed BudgetExceededError with these fields.
When the budget can’t be read
If an agent has a cap and the budget, today’s spend or the in-flight total can’t be read, the call is held instead of running uncapped:BudgetExceededError; the SDKs surface it as an ordinary request failure. Agents with no cap never get it.
Alerts
Atalert_at the agent gets a budget_warning notification. When a call is blocked, it gets budget_exceeded. Both appear in notifications, which the agent can read, and are emailed if alert_email is set. Each fires at most once per UTC day.
Authentication
Both budget endpoints identify the agent byX-Agent-ID and require a signed x-agent-proof (read proof): scope: "read" for GET, scope: "write" for PUT. Unlike inbox and notification reads, this is not log-only. A budget write under a spoofed public wallet address could halt another agent’s paid calls, so unsigned requests are rejected.
The SDKs sign automatically (TypeScript ≥ 0.27.0, Python ≥ 0.20.0) and sync a budgets config once, before the first paid call.