Skip to main content

Set a Budget

Tasks

Create a rule to cap spend for an organization, team, or user, set a hard session-level cap, and configure the alerts that notify you as spend approaches those limits.

Create a budget rule​

  1. Navigate to Cost → Budgets → Rules.

  2. Click + New rule in the top-right corner and choose a starting template:

    TemplateUse for
    Org spend ceilingGlobal limit across all models for the whole organization
    Team budgetTotal cap for one team across all models
    Model capLimit one model family (e.g. claude-opus*) at any scope
    Blank ruleStart from scratch
  3. Set the rule's Scope — Global (all identities), Team (a named group), or User (a specific identity) — and its Target (the team name or user email, or * for Global).

  4. Set the Model match — a glob pattern such as claude-opus*, gpt-4o, or * for all models. The first matching rule within each scope applies.

  5. Set the Limit (maximum spend in USD) and the Window — Hourly (1h), Daily (24h), Weekly (7d), or Monthly (30d). Each resets on a fixed calendar boundary, not a trailing period counting back from now: Hourly resets at the top of each hour, Daily at midnight UTC, Weekly every Monday, and Monthly on the 1st. A rule created partway through a period only covers the remainder of it before the first reset.

  6. Choose what happens when the limit is reached:

    ModeWhat happens
    DenyRequests are blocked until the window resets.
    AuditRequests are allowed; overage is tracked and shown in the Overview "Audit-mode Overage" tile.
    WarnRequests are allowed and recorded as a warning.
    Require approvalRequests are held for a manager to approve or deny in the Approvals queue.
  7. Set Warn at — the percentage of the limit at which a budget_warning notification fires, once per rule per window, for as long as spend stays under the hard limit. Default: 80%. Requests above the threshold are still allowed and are recorded as warnings.

  8. Save the rule. Use the Effective budget inspector at the top of the Rules tab to type any identity and model and confirm which rules bind, the remaining headroom, and the decision for the next request.

note

Model match must be unique within a scope — you can't have two rules in the same scope (e.g. two Global rules) that both match claude-opus*, even with different windows. Only the first matching rule in a scope is ever enforced, so a second rule for the same match would silently do nothing, and anything that targets a rule by its match alone — raising its limit via an approval — could no longer tell the two apart. Saving a second rule for a match already present in the scope is rejected; edit the existing rule's limit or window instead. Two rules with different model-match patterns, even overlapping ones like claude-opus* and *, are both allowed and both enforce independently.

note

Rules are AND-enforced: a request must pass the first matching rule in every applicable scope (global, team, user — plus agent and token, configurable via the API; see the warning below). If multiple rules match a request, all of them apply.

warning

If you (or an integration) configured an agent- or token-scoped budget rule directly via the API — the Rules UI currently only exposes Global/Team/User — that rule now enforces for the first time. Previously, agent- and token-scoped rules were saved successfully but silently never matched any request; if you have one, verify its limit is still what you intend before your next request hits it. The Effective budget inspector will now show these rules binding where it previously showed nothing.

tip

To promote an audit-mode rule to Deny once you've reviewed the overage it would have caught, use the one-click promote action from the Overview tab.

Set the default session cap​

  1. Navigate to Cost → Budgets → Limits.

  2. Set Default session cap — the maximum spend (USD) for any single session. When a session hits this cap, further requests are blocked until the session ends or an admin resets it. Set to 0 to disable.

Individual sessions can override the default via their PAT settings.

Configure alerts​

Alerts notify you as spend approaches a limit — they do not, on their own, block requests. Configure them in Cost → Budgets → Alerts.

When a limit is actually reached and a rule in Deny or Require approval mode starts blocking or holding requests, AIControls sends a budget_exceeded notification to administrators without any further configuration: once per rule per window (not once per blocked request, and only once across all replicas), naming the scope (organization, team, user, agent, or token), the model match, the window, the spend against the limit, when the window resets, and which identity tripped it. It is delivered to the in-app inbox and, when configured, email, Slack, Teams, and webhooks — turn channels on or off under Settings → Notifications → Budget Exceeded. The same applies to per-agent token budgets on hourly/daily/weekly/monthly windows and to a developer's monthly cap — except the 1-minute tokens-per-minute (TPM) rate limit, which fires rate_limit_exceeded instead, not budget_exceeded. Rules in Audit or Warn mode never block, so they never send budget_exceeded; use Warn at for those.

  1. Under Budget warning thresholds, add one or more percentage values (e.g. 75, 90). Each threshold fires a budget_warning notification at most once per window per rule. (Per-model rules use their own Warn at percentage instead, as described in Create a budget rule, with the delivery noted below.) budget_warning is an administrator-facing notification — it names the developer, team, or agent whose spend tripped it, but is delivered to:

    • Email, Slack, or Teams, if configured (to the admin-configured recipients — not the affected developer's own inbox or address)
    • Administrators' in-app inbox — for per-model Warn at only; the thresholds set here do not create an in-app entry, so configure at least one external channel if you rely on them
  2. Under Session spend alert, set a USD threshold at which an in-app notification fires the first time a session's spend crosses that value. Set to 0 to disable. This is independent of the session cap configured in Limits — it only notifies, it does not block requests.

note

For conditional enforcement near a budget threshold — for example, requiring a ticket ID once spend exceeds 80% — use a CEL policy with object.modelBudget.team.pctUsed.

What users see when a budget is reached​

Generation-endpoint budget denials are delivered in the format the developer's tool already decodes, with one readable message that starts Blocked by AIControls: and names the budget, the spend against its limit, and how to get more headroom. The /v1/messages/count_tokens endpoint is an exception: it keeps an Anthropic error envelope because it has no assistant-turn response shape.

ClientWhat the developer sees
Claude Code (Anthropic Messages API)An assistant message in the conversation beginning Blocked by AIControls: — for example Blocked by AIControls: monthly budget exhausted ($52.10 of $50.00 used). Visit https://YOUR_WORKSPACE_URL/dev/me to request more budget. It is a normal turn, not an API Error banner, and Claude Code does not retry it.
Codex (Responses API)The same message printed as an error line in the transcript (■ Blocked by AIControls: …). Codex treats it as final and does not retry; typing another prompt sends a new request, which is denied the same way until the window resets or more budget is granted.
Cursor and other OpenAI-compatible tools (Chat Completions API)An HTTP error whose message is Blocked by AIControls: …, shown however the tool reports a rejected API call — except a per-model rule with exceptions enabled (see below), which arrives as a normal 200 assistant turn offering the exception, the same as Claude Code.
Claude-on-Bedrock (via InvokeModel) and Vertex passthroughClaude-on-Bedrock's InvokeModel API and Claude-on-Vertex's rawPredict both speak the Anthropic envelope, so a denial matches the request's own shape; native Gemini requests use the Google API envelope. Bedrock's Converse API and non-Claude Bedrock model families (Nova, Titan, Llama, Mistral, Cohere) are not covered by this wire-format guarantee — a denial there is still sent in the Anthropic envelope regardless of the request's actual shape.

Which budget produced the message determines its wording:

BudgetMessage
Per-model rule (Deny mode)model budget exceeded: spent $X / limit $Y for <model pattern> (<scope> scope) in window <window> — and, when exception requests are enabled, the message is an assistant turn that also offers a time-bounded exception (see Exceptions). Reply request exception: <reason> to file it.
Monthly developer or team budgetmonthly budget exhausted ($X of $Y used), with a link to the developer portal to request more budget.
Session capSession budget reached ($X of $Y used), with the option to request a session top-up.
Virtual key spend capvirtual key budget exhausted: … naming the key's cap.
Token budget (hourly or longer window)token budget exceeded: used N / limit M in window <window>.

Per-minute rate limits (requests or tokens per minute) are the one exception: they are transient, so they are returned as a 429 with a Retry-After header and the developer's tool retries automatically once the minute rolls over.

A rule in Require approval mode does not deny at all — the request is held for a reviewer, and the developer's tool waits; see What the developer sees under approval workflows.

Exceptions​

A developer denied by a model-cap rule can be granted a time-bounded exception: an approved exception targeting controller budget.model-cap, scoped to the same team/user/agent/token tier as the rule, with the model pattern (e.g. claude-opus*) as its subject, adds the exception's USD amount to that rule's limit for the developer's next request. When the exception expires (or is revoked), the added amount is dropped automatically — no cleanup needed.

Policies can read the resolved, exception-adjusted limits as object.defaults.budget.limits. See Request a config-target exception for how a developer requests one and how you approve it.

note

This is a durable, rolling-cap exception — separate from a one-time, single-session top-up. If a developer just needs a bit more headroom to finish their current session, see Grant a session budget top-up instead; approving one never affects the other.

See also​