How it differs from maxCost
Use both:
maxCost is a per-call sanity check; the budget is the guardrail.
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 squeeze under the cap. The reservation is released once the receipt lands. If Redis is unavailable the guard degrades to a best-effort ledger check (fails open) rather than blocking payments.
- Calls fully covered by credits don’t consume budget. Failed settlements don’t count as spend.
reason is daily or per_transaction. The SDKs raise a typed BudgetExceededError carrying these fields.
Alerts
Atalert_at the agent gets a budget_warning notification; when a call is blocked it gets budget_exceeded. Both land in notifications — the agent itself can read them — and, if an alert_email is set, by email. 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 the 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 outright.
The SDKs sign this automatically (TypeScript ≥ 0.27.0, Python ≥ 0.20.0) and sync a budgets config once, before the first paid call.