Managed Agents API requests require the
managed-agents-2026-04-01 beta header, except memory store endpoints, which use agent-memory-2026-07-22 instead. The SDK sets the correct beta header automatically. See Beta headers.Set a budget at session creation
Pass the optionalbudget field when you create the session:
budget object has two fields:
typeis always"limit".max_list_costis the cap itself:amountis a whole number of US cents written as a string with no leading zeros ("125"is $1.25 and"50"is 50 cents) and must be greater than zero. Decimal forms such as"25.00"are rejected. The amount is a string rather than a number so no float rounding is ever applied to it.currencyis an uppercase ISO-4217 currency code;USDis the only supported currency.
How list cost is measured
The platform prices what the session consumes, continuously, at public list rates:- Model tokens, at each served model’s list price
- Web searches, at $10 per 1,000 searches
- Session running time, at $0.08 per hour
list_cost figures reported on the session and its events are whole cents, rounded to the nearest cent, so a reported figure can read up to half a cent either side of the exact amount enforcement uses.
When a session reaches its budget
The cap is enforced between model requests, not mid-request. Before each model request, the platform checks the session’s consumed list cost, and once that total reaches the cap every thread pauses before its next request. The request that carried the total past the cap was admitted while the session was still under it and runs to completion, so a paused session’s recordedlist_cost reads at or a fraction past max_list_cost: a session capped at "50" (50 cents) can pause with a list_cost of "53". This is expected, not a billing error, and the overshoot is bounded by one model request per thread. Treat the budget as a bound on new work rather than an exact stopping point, and size the cap with that one-request margin in mind.
A session that reaches its budget goes idle with a stop_reason of budget_reached; it is not terminated, and its history and sandbox are preserved like any other idle session’s. On the event stream you’ll see, in order:
- A
session.thread_status_idleevent with astop_reasonofbudget_reachedas each thread pauses. - A
session.usageevent with the session’s cumulative usage and list cost. - A
session.status_idleevent with astop_reasonofbudget_reached. The usage event always immediately precedes this idle event.
end_turn on its own session.thread_status_idle event while the session still reports budget_reached; treat the session-level stop_reason as the signal that the session paused at its budget.
Events accepted at the cap
While the session is at or over its budget, it accepts only events that settle work already in progress:user.tool_confirmationuser.tool_resultuser.custom_tool_resultuser.interrupt
user.message, is rejected with a 400 error naming this list. Settled results are recorded without triggering a new model request; the session stays paused at its budget.
A user.interrupt sent while the session is paused at its budget (all threads paused at the cap) is accepted and ignored: it does not appear in the event list and changes nothing. Change or remove the budget to continue.
Resume a session at its budget
Change or remove the budget with a session update. An accepted update resumes the session’s paused work automatically; no further client action is needed.Change the budget
Update the session with a newmax_list_cost. The new value can be higher or lower than the current cap, but it must be strictly greater than the session’s consumed list cost; otherwise the update is rejected with a 400 error: budget.max_list_cost must be greater than the session's consumed list cost. Because the consumed cost usually sits a fraction past the old cap when the session pauses, base the new value on the session’s reported usage.list_cost, not on the old max_list_cost. Set it a cent or more above that figure: the reported value is rounded and can sit a fraction below the exact consumed cost the check uses.
Remove the budget
Setbudget to null to remove the cap entirely. The session’s paused work resumes, and the resulting session.updated event carries budget set to null.
Monitor spend
The session object carries itsbudget and a usage object with the tracked spend: usage.list_cost is the session’s consumed list cost, and usage.active_seconds is the running time its runtime cost is priced on. On a session paused at budget_reached, expect usage.list_cost to read at or a fraction past max_list_cost: the request that crossed the cap finished before the pause. Session-level active_seconds counts overlapping activity from concurrent threads once. Thread retrieval responses carry the same two fields on the thread’s own usage, priced per thread. Per-thread figures are rounded independently and exclude the session’s running-time cost, so they don’t sum exactly to the session’s list_cost; the session figure is the one the budget is enforced against.
The session.usage event is a snapshot of the session’s cumulative usage and tracked list cost. It carries the session’s token totals, list_cost, active_seconds, server_tool_use request counts (web_search_requests, priced into list cost per request, and web_fetch_requests, which reads 0 because web fetch requests carry no per-request charge and aren’t metered), and an echo of the session’s budget, or null when the session has none. It appears in the events list and the session stream. The session emits one immediately before it goes idle, whatever the stop reason, so a session that reaches its budget always emits one immediately before the budget-reached idle event.
For reading usage from the stream and the session object, see Tracking usage.
Budgets in multiagent sessions
A multiagent session has a single budget shared across all of its threads; there are no per-thread caps. Each thread’s consumption is priced at its own served model, and threads pause independently as the shared cap is reached. Advisor consultations count against the same budget, priced at the advisor model’s rates. One thread can pause atbudget_reached while another finishes its in-flight request.
A pending ask outranks the cap: a session with one thread waiting on requires_action and another paused at budget_reached reports requires_action at the session level. The pending request still needs an answer, and answering it is a settle event the budget doesn’t block.
Budgets on deployments
A deployment accepts the samebudget object when you create or update it:
null and set again later. See Set a budget on each run.
Models without a list price
A budget can only track consumption the platform can price. Creating a budgeted session whose agent, or any agent or advisor on its multiagent roster, uses a model with no public list price is rejected with a 400 error stating that no list price is available for the model. If a budgeted session’s usage comes to include a model with no list price, the budget can no longer measure the session’s spend: the session can pause with astop_reason of budget_reached, and changing the budget is rejected. Remove the budget to resume the session.
Error reference
Budget-related requests are rejected in the following cases:Session budgets are hard caps in US dollars (written in cents) on a single session, enforced by the platform. They are distinct from the Messages API’s task budgets, which are advisory, token-denominated budgets the model uses to self-regulate within one agentic loop.