How to Cap AI Usage Per Customer in Your App
The vendor dashboard caps your whole organisation and the billing meter is too slow to stop anything. The per-customer gate has to be yours, and what it does when it trips is a product decision.
How to cap AI usage per customer comes down to one design decision, not a feature: where the counter lives. The vendor's dashboard can cap your whole organisation, and your billing system can measure what a customer owes, but neither can stop one customer's thirtieth document of the afternoon before it costs you money. That gate has to sit in your own code, in front of the API call, and the interesting question is what it does when it trips.
There are three honest answers to that, and they produce very different products.
Why the vendor's cap is not your cap
Provider controls are real and they are the wrong shape. Anthropic's rate limit documentation describes spend limits that set "a maximum monthly cost an organization can incur" and per-workspace controls, noting that you can "set custom spend and rate limits per Workspace" to "protect Workspaces in your Organization from potential overuse".
That is per workspace, not per customer, and the behaviour when it trips makes the point. The docs explain that once a tier spend cap is reached, "API usage pauses until 00:00 UTC on the first day of the next month" and requests return a 429 carrying no retry-after header, so "retrying, including the SDK's automatic retries, fails until access resumes". Your heaviest customer has just taken your entire product offline for every other customer until the first of the month.
A per-workspace limit helps if each customer has their own workspace, which is rare outside enterprise deployments. For everyone else the provider cap is a backstop against catastrophe, not a product control.
Why the billing meter is not your cap either
The second common mistake is assuming the usage meter you already send events to can enforce a limit. It is a ledger, not a gate, and the latency is documented. Stripe's guidance on recording usage states that "Stripe processes meter events asynchronously, so aggregated usage in meter event summaries and on upcoming invoices might not immediately reflect recently received meter events".
Asynchronous is fine for an invoice and useless for a gate. In the seconds between a customer's request and the meter reflecting it, they can send another hundred. Send events to the meter for billing, and keep a separate counter you read synchronously for enforcement. The two will disagree slightly and that is correct: one is money, the other is a limit.
Where the counter goes
Put it in front of the call, keyed by customer, in whatever store you can read in single-digit milliseconds. A row in your own database works at small scale. Redis or an equivalent is the usual answer once concurrency matters, because the increment has to be atomic: two simultaneous requests that both read "999 of 1000" will both proceed.
Count the thing that costs you money, which is usually tokens rather than requests. A request limit is easy to explain and easy to game, since one request with a long document can cost more than fifty short ones. Counting tokens means reading the usage figures off each response and adding them after the fact, so expect a small overshoot on the final call and set the limit with that in mind.
# before the call
used = counter.get(customer_id, period)
if used >= plan.token_limit:
return over_limit_response(plan) # see the three behaviours below
resp = client.messages.create(...)
# after the call, atomically
counter.incr(customer_id, period,
resp.usage.input_tokens + resp.usage.output_tokens)Reset by billing period rather than by calendar month if your subscriptions renew on different days, otherwise a customer who signs up on the 28th gets three days of allowance for a month's money, and will say so.
Decide what a customer is
The word customer hides a decision when your accounts have teams in them. A limit set per user lets a ten-seat account consume ten allowances, which is usually what they paid for. A limit set per account means one enthusiastic colleague can exhaust the team's month on a Tuesday, and the complaint arrives from the eight people who did nothing.
The arrangement that survives contact with customers is both: an account-level cap that protects your margin, plus a per-user share that protects colleagues from each other, with an account admin able to move the shares around. That last part matters more than it sounds, because it converts a support request into a setting.
Count against the account that pays, not the user who clicked, and store both numbers. You will want the per-user figure later anyway, when someone asks which team is driving the bill.
The three things a cap can do when it trips
Behaviour | What the customer sees | Best for |
|---|---|---|
Hard refuse | The feature stops with a clear message | Free tiers and trials |
Degrade | It keeps working, on a cheaper model | Paid plans with a margin to protect |
Queue until reset | The request completes later | Batch and background work |
Hard refuse is the honest option and the one to default to on a free tier, because the alternative is a free user with unlimited variable cost. Say the limit, say when it resets, and offer the upgrade path without making the message a sales pitch.
Degrading is the strongest choice for paid plans and the most work. Moving a customer to a smaller model at 80 percent of their allowance keeps the product usable and cuts the marginal cost substantially. The risk is silence: a customer whose output quality drops without explanation concludes your product got worse. Tell them, in the interface, at the moment it happens.
Queueing suits anything the customer is not watching. It is the wrong answer for an interactive feature, where a delayed response is indistinguishable from a broken one.
What to tell the customer, and when
At 80 percent, a quiet notice in the interface with the number and the reset date.
At 100 percent, the behaviour you chose, stated plainly, with what changes and when it ends.
Always a visible usage figure somewhere in the account, because a limit nobody can see reads as arbitrary.
Never a surprise. A cap discovered at the moment of failure is a support ticket; a cap visible for a week is a pricing decision the customer made.
Set the number from your own distribution rather than from a round figure. The percentile method in how much an AI feature costs per user is the right input here: the average tells you nothing, and the heavy decile tells you where the cap has to sit to protect the plan.
A cap is a pricing decision
Once the counter exists, the limit itself becomes a product lever rather than an engineering constant. A generous cap with a hard refuse is a different proposition from a tight cap that degrades, and both are different from metered overage, where the cap becomes a billing trigger instead of a wall.
Which of those fits depends on the structure you have chosen, and that is the subject of per-seat versus usage-based pricing for an AI product and of whether to charge extra for an AI feature at all. The wider set of options sits in AI monetization strategies. For internal tooling rather than a customer-facing product the equivalent exercise is setting a budget cap on an AI coding agent, where the trade-offs land in a different place because the person hitting the cap works for you.
FAQ
Should the cap be on tokens or on actions?
Count tokens internally, express the limit in actions externally. Customers cannot reason about tokens, so "200 summaries a month" is a better plan description than a token figure, as long as your counter is measuring the thing that actually costs you money.
What about one customer with a legitimate spike?
Build a manual override before you need it. A support person being able to raise one customer's limit for one period, with an audit entry, prevents the alternative, which is an engineer editing the database during a bad week.
Do I need this on day one?
You need the counter on day one and the cap can come later. Measuring per-customer usage from the first week costs almost nothing and tells you where to set the limit. Retrofitting the measurement after a surprise invoice is the expensive order to do it in.
Can I rely on prompt caching to make this unnecessary?
Caching reduces cost and does not bound it. It helps most when customers repeat the same context, which is exactly the pattern where usage is already cheap. The expensive customer is the one sending new material every time.
How did this land?
About the author

Staff Engineer, Platform
Carlo works on the platform that turns prompts into running apps. He writes the engineering deep dives and the changelog notes worth reading.


