Перейти к основному содержимому

Hard Spend Caps: Which AI Providers Actually Stop the Bill

Средний

On October 3, 2026, Simon Willison published a short argument that landed on the Hacker News front page with 615 points: usage-billed services need hard budget caps by default, with uncapped billing as the explicit opt-in. His framing is the one that matters — "Nobody wants to wake up to an email sent at midnight warning about a budget limit and find that, while they slept, their rogue service had consumed several hundred (or several thousand) more dollars."

The reason this became a 2026 argument rather than a 2015 one is that agents changed the shape of the risk. A human misconfiguring a cron job is a slow leak. An agent that retries a failing tool call in a loop, or spawns subagents that spawn subagents, is a leak with a model behind it — and it runs at machine speed while you sleep.

The good news: in the last four months, most of the stack quietly grew real caps. The bad news is what this page is actually about — the caps exist, but they announce themselves with four different HTTP status codes, and at least two of them will be swallowed by the retry logic you already wrote.

What you'll learn
  • Tell a soft cap (an email) from a hard cap (a blocked request) — and know which one each provider gives you
  • Handle the four different error shapes a spend cap can return, including the one that arrives as a 400 your retry logic treats as a bug
  • Understand why no cap on the market can be exact, and why every vendor disclaims liability for the overage
  • Know where Anthropic's default safety net disappears, and what the Enterprise Spend Limits API replaces it with
  • Put a real ceiling under a new project in about twenty minutes, at the layer that actually blocks

Soft cap vs hard cap: the only distinction that matters​

Strip away the marketing and every spend control is one of two things.

A soft cap observes. It watches a cost signal, compares it to your number, and notifies — email, webhook, dashboard badge. Traffic keeps flowing. AWS Budgets, Anthropic's usage dashboard, and every "billing alert" you have ever configured are soft caps. They are genuinely useful, and they are not protection: a soft cap's only effect is to tell a human to intervene, which means its latency is your response time, not the system's.

A hard cap enforces. It blocks new requests at the limit. Your code finds out through an error, not an inbox.

The practical test: if every human on the team is asleep, does the spend stop? If the answer is no, it is a soft cap no matter what the UI calls it.

Everything below is about hard caps. Keep your soft caps too — a cap that fires is an incident, and you want the warning at 60% as well as the block at 100%.

Which providers actually block​

Provider / layerHard cap?ScopeWhat you get when it fires
Anthropic — tier capYes, by defaultOrganization, monthlyHTTP 429, rate_limit_error, no retry-after, details.error_code: enforced_spend_limit_reached
Anthropic — limit you setYes, opt-inOrganization or workspaceHTTP 400, invalid_request_error, message begins "You have reached your specified API usage limits"
Anthropic — Claude Code workspaceYesThat workspaceChecked separately; can return a 429 that does carry retry-after
OpenAI — hard spend limitYes, opt-inOrganization and/or projectHTTP 429
OpenRouter — credits / key capYes, structurallyAccount balance, per-keyHTTP 402, with error.metadata.limit_source
Google Cloud — spend cap budgetYes, opt-in (Preview)One project × one serviceNew usage for that service blocked until manually lifted
AWS — project spend limitYes, new accountsPer projectProject paused rather than accruing further charges
LiteLLM / self-hosted gatewayYes, pre-flightKey, user, team, modelAuth-shaped error, raised before the provider is called
Claude Code telemetryNo—Observability only; exports cost, enforces nothing

The trap: four status codes, one event​

This is the part that is documented in four separate places and assembled nowhere, and it is the thing most likely to bite you.

Read the Anthropic behaviour carefully, because it is two different behaviours.

When you cross your tier's monthly cap, the API returns HTTP 429 with error type rate_limit_error — the same type as an ordinary rate limit — but with no retry-after header. Anthropic's own documentation is blunt about the consequence: "Retrying, including the SDK's automatic retries, fails until access resumes." Access resumes at 00:00 UTC on the first of the next month unless you raise the limit. So a well-behaved client with exponential backoff will sit in a retry loop for up to 31 days, logging transient-looking errors. The distinguishing field is error.details.error_code, which is enforced_spend_limit_reached.

When you cross a limit you configured — organization or workspace — the API returns HTTP 400 with type invalid_request_error. That inverts the usual assumption: a 400 means "your request was malformed, do not retry," so most clients log it as a bug and either crash or drop the work silently. It is not a bug; it is your own cap doing its job.

And the Claude Code workspace is checked separately again: requests over that workspace's limit can receive a 429 that does carry retry-after.

OpenRouter takes the third route. Because the model is prepaid credits, running out is a payment problem, so it returns HTTP 402 Payment Required, with error.metadata.limit_source naming which of the three limits you hit — account balance, per-key cap, or the in-flight budget hold. One detail worth knowing: when the account balance goes negative, requests to free models fail too.

OpenAI's documentation states that requests affected by a hard spend limit return a 429. It does not state an enforcement latency, and it distinguishes two things that are easy to conflate: the approved monthly usage limit OpenAI sets for your organization, and the spend limits you configure yourself on an organization or a project. Both can apply to one request, so a project with headroom can still be blocked by the organization ceiling above it.

Four shapes for one event. Which means the handler you want is not "retry on 429."

Classify a cap error instead of retrying it

# The three signals that mean "stop, this is a budget wall" — not "wait and retry"
#
#   Anthropic tier cap   -> 429, type=rate_limit_error, NO retry-after,
#                           error.details.error_code == "enforced_spend_limit_reached"
#   Anthropic own limit  -> 400, type=invalid_request_error,
#                           message startswith "You have reached your specified API usage limits"
#   OpenRouter           -> 402, error.metadata.limit_source present
#   OpenAI hard limit    -> 429  (no documented discriminator field)

def is_budget_wall(status, body, headers):
  err = (body or {}).get("error", {}) or {}
  detail_code = (err.get("details") or {}).get("error_code")

  if status == 429 and detail_code == "enforced_spend_limit_reached":
      return True                      # month-long wall; do NOT back off
  if status == 429 and "retry-after" not in {k.lower() for k in headers}:
      return True                      # 429 with no retry-after is not a rate limit
  if status == 400 and err.get("message", "").startswith(
      "You have reached your specified API usage limits"
  ):
      return True                      # your own cap, wearing a 400
  if status == 402 and (err.get("metadata") or {}).get("limit_source"):
      return True                      # prepaid balance or key cap

  return False

# Page a human, mark the work as blocked, and stop the loop.
# Retrying a budget wall just burns your own CPU until the first of the month.

The general rule that survives any provider's refactor: a 429 without a retry-after header is not a rate limit. Rate limits are temporary by construction and tell you how long to wait. A 429 that refuses to tell you how long is a different animal.

Why no cap can be exact — and why that is not laziness​

Every hard cap on the market fires on estimated cost, not billed cost. This looks like a shortcut and is in fact the only workable design: a billing pipeline that aggregates, rates, applies discounts and reconciles usage takes minutes to hours. A cap that waited for it would be useless against exactly the failure mode it exists to stop.

Google Cloud states the trade-off plainly: "For faster enforcement, spend caps use gross, estimated costs to trigger alerts and enforce the spend cap" — and then, honestly, "Due to latency in usage and cost reporting, spend cap enforcement isn't instantaneous. Consider setting your budget slightly below your absolute limit." And the liability: "any cost overages are billed as normal." You remain responsible for what leaks through during the reporting lag.

Three consequences you should design around:

Set the cap below your real ceiling. If $500 is the number that genuinely hurts, cap at $400. The gap is your overshoot budget. How big it needs to be depends on your peak burn rate, not on the provider — an agent fleet that can spend $50/minute needs a wider margin than a chat app that spends $50/day.

In-flight requests complete. A cap blocks new usage. Anything already in flight finishes and bills. With long-running agent turns this is not a rounding error.

Pre-flight beats post-hoc. The only mechanism that structurally avoids overshoot is reserving the estimated cost before the call. LiteLLM's proxy does this by default: it estimates the maximum cost from the request body and the model's pricing, holds that amount against every applicable budget, rejects the request if the reservation would breach the budget, then swaps the reservation for the actual cost once the response lands. OpenRouter's in-flight budget hold is the same idea applied to a prepaid balance. Both are strictly stronger than measuring after the fact, and both are only approximate in the other direction — they over-reserve, which means they can refuse a request you could have afforded.

Anthropic's tiers, and where the net disappears​

Anthropic gives you a hard cap whether or not you ask for one. The Start, Build and Scale tiers each carry a monthly spend cap — the maximum your organization can spend on the API in a calendar month.

Usage tierMonthly spend cap
Start$500
Build$1,000
Scale$200,000
CustomNone — arranged with your account team

Read the last row again. The default safety net exists on every tier except the one occupied by the organizations spending the most. Graduating to Custom removes the automatic ceiling, which makes an explicitly configured limit mandatory rather than optional at exactly the point where people stop thinking about it.

Two more things worth setting while you are in there:

Set your own limit below the tier cap. The Billing page takes a number lower than your tier's cap. This is the control you actually want, because you choose it — and remember it surfaces as a 400, not a 429.

Use workspaces as blast-radius boundaries. Workspaces take their own spend and rate limits, so an experimental agent and your production traffic do not share one pool. Organization-wide limits always apply on top, even if the workspace limits sum to more. One restriction: you cannot set limits on the default workspace — so do not put anything you care about there.

The Enterprise layer: per-member caps as an API​

Claude Enterprise organizations get something the Console does not expose: a Spend Limits API, which treats per-person budgets as a resource you can read and write programmatically. It is the piece of this story that is barely written about anywhere, so it is worth knowing what it does.

Eight endpoints across two resources. The first answers "what cap applies to each member, where did it come from, and how close are they to it":

Read every member's effective cap and month-to-date spend

curl "https://api.anthropic.com/v1/organizations/spend_limits/effective?limit=20" \
--header "x-api-key: $ANTHROPIC_ADMIN_KEY" \
--header "anthropic-version: 2023-06-01"

# Each row carries:
#   amount                -> the effective cap, in MINOR UNITS ("50000" = $500.00)
#                            null = unlimited;  "0" = included plan usage only
#   source.type           -> user | seat_tier | rbac_group | organization
#   period_to_date_spend  -> spend since the period started, same minor-unit format
#   spend_limit_id        -> the configured row this resolved from
#
# Requires an Admin API key with the read:spend_limits scope.

Four details in there that will cost you an afternoon if you miss them:

  • Amounts are decimal strings in minor units of the billing currency. "50000" is $500.00. Parse as a decimal and divide by 100 — the docs explicitly warn against binary floating point for large values.
  • null and "0" are not the same. On a member's effective row, null means unlimited; "0" means the member cannot use Claude beyond their plan's included usage. Treat "0" as already at-limit.
  • period_to_date_spend can read "0" when the reading is simply unavailable. The docs call it informational, not transactional — so do not build a gate that treats a zero reading as "no spend."
  • A group limit is a per-member default, not a pooled budget. Each member inheriting it is gated against their own spend.

The second resource is a review queue. When a member clicks "Request more usage" in claude.ai, a spend-limit increase request appears; you can list pending ones, and each carries a live spend_summary with that member's current cap and period-to-date spend, so a policy engine can decide without a second lookup. Approving writes the new per-user cap in the same call. Two asymmetries to know: setting a limit directly with POST /spend_limits does not resolve a pending request (use the approve endpoint), and all eight endpoints share one 60-requests-per-minute budget per organization.

You can only write per-user overrides through this API. Seat-tier, group and organization defaults are configured in claude.ai settings. And the API is Enterprise-only — it is not available to Claude Platform (Console) organizations.

For reporting rather than enforcement, the companion is the Usage & Cost Analytics API — GET /v1/organizations/analytics/cost, which groups spend by model, workspace, API key, actor, cost_type and token_type. That cost_type split is how you find out that your bill is not mostly inference. The older GET /v1/organizations/cost_report still works but Anthropic marked it legacy on October 29, 2026; it returns daily buckets (default 1d, at most 31 per page) with amounts in minor units, groupable by description or workspace_id. Two differences matter before you swap one for the other: the new API needs the anthropic-beta: analytics-usage-cost-2026-08-24 header, and its data lags 4–24 hours instead of ~5 minutes — so it reports, while the spend-limit endpoints above enforce.

Put a ceiling under a project​

Guided walkthrough1 of 7
  1. Pick the figure at which you would want everything to stop, and set the cap 20-25% under it. That margin absorbs reporting lag and in-flight requests. Write the number down somewhere a future teammate will find it, because an unexplained cap gets raised during the first incident.

The cloud layer, and what it does not cover​

Google Cloud shipped spend cap budgets in its July 27, 2026 billing release notes — in Preview, with notably little fanfare for a feature that topped billing feature requests for a decade. The mechanics are worth reading closely, because the scope is narrower than "a hard cap on Google Cloud":

  • Eligible services are a short list — as documented: Gemini API, Gemini Enterprise Agent Platform, Cloud Run, and Cloud Run functions. Check the current list before you rely on it; a cap on a service that is not eligible does not exist.
  • One cap covers one project × one service. Not an account-wide killswitch.
  • Monthly periods only.
  • It does not auto-resume. "When a spend cap is enforced, the usage block is reversed only when you manually lift the spend cap" — and services can take up to an hour to fully resume afterwards. For a production service, that is a deliberate outage you are choosing over a deliberate bill. Decide which one you want before you set the cap.
  • Persistent resources keep charging. Fixed usage tied to compute and storage stays active and keeps accruing. The cap stops new requests, not your running infrastructure.
  • Subscription costs are excluded — Gemini Enterprise licences, for example.

AWS went the other way and attacked the problem at signup. Reported on September 17, 2026, new AWS accounts arrive structured as a project, start with $100 in Free Tier credits, and on moving to paid get a monthly spend limit per project starting at $20, with AWS suggesting a figure from prior usage. At the limit the project is paused rather than accruing charges, and it resumes when the owner raises the cap. Two caveats: the rollout is gradual and covers new customers only, and what a paused project does to a live public endpoint is not spelled out — which, for anything user-facing, is the question you need answered first.

What caps will not save you from​

A hard cap is a ceiling on metered usage at one layer. Four things routinely sit outside it:

Seats and subscriptions. Per-seat licences and plan fees are not metered usage and are not capped by a usage cap.

Persistent infrastructure. Idle GPU instances, provisioned databases and storage keep billing while your API cap is enforced. The agent stopped; the machine it was running on did not.

Coding agents on their own clock. Claude Code exports cost telemetry — claude_code.cost.usage in USD and claude_code.token.usage in tokens, both incremented after each API request, attributed by model, query source (main / subagent / auxiliary), speed and effort. That is genuinely good observability, and it enforces nothing: the metrics are read-only exports emitted after each request completes. The enforcement has to live at the API or gateway layer underneath. Set a Claude Code workspace limit, and remember that workspace is checked separately from the rest of your organization.

The gap between layers. A gateway budget does not help if a service can reach the provider directly. The provider-level cap is the only one that cannot be routed around — which is why it goes first.

Check yourself

0/6
  1. Your Anthropic client starts receiving HTTP 429 with error type rate_limit_error, but no retry-after header. What is the most likely cause, and what should the client do?
  2. You set your own spend limit in the Anthropic Console, below your tier cap. What does the API return once you cross it?
  3. Why do all the hard caps on the market fire on estimated rather than billed cost?
  4. Which Anthropic usage tier has no default monthly spend cap?
  5. What makes LiteLLM's budget reservation structurally stronger than measuring spend after each call?
  6. A Google Cloud spend cap is enforced on your project. Which of these keeps costing you money?
Нажмите Enter или пробел, чтобы перевернуть карточку. Используйте стрелки влево и вправо для перехода между карточками.Показан термин.
1 / 12
Key takeaways
  • A soft cap's latency is your response time. If nobody is awake, it is not a control.
  • One event, four status codes: 429-without-retry-after (Anthropic tier), 400 (your own Anthropic limit), 429 (OpenAI), 402 (OpenRouter). Generic retry logic mishandles at least two.
  • A 429 with no retry-after header is never a rate limit. That one heuristic catches the worst failure mode — a client retrying a month-long wall.
  • Every cap fires on estimated cost and every vendor disclaims the overage. Cap 20-25% below the number that would actually hurt.
  • Anthropic's Custom tier has no default monthly cap — the safety net vanishes where the spend is biggest.
  • Pre-flight reservation (LiteLLM, OpenRouter's in-flight hold) is the only design that holds under concurrent agent bursts. Post-hoc measurement always overshoots.
  • Cap the provider first — it is the only layer that cannot be routed around. Gateway and app limits are defence in depth.
  • A cap you have never watched fire is a belief. Set a throwaway key to a few cents and read the real status code your stack receives.

Next​

Sources & further reading​