Answers · agent payments
My app lets customers chat with an AI agent on my API key. How do I stop one user, or a script pretending to be users, from running up my LLM bill?
Last updated
TL;DR: Give every end user their own budget in your own code or gateway, because the provider can't tell your users apart. OpenAI and Anthropic spend limits apply to an organization, project or workspace, so when one heavy user hits the cap, every user on that key starts getting errors (OpenAI returns 429 project_spend_limit_exceeded). OWASP lists this as LLM10:2025 Unbounded Consumption and names the attack Denial of Wallet: running up a pay-per-use AI bill on purpose. The fix it recommends is rate limits and per-user quotas, input size limits, timeouts and monitoring. In practice: identify the user on your server (from their session, never from a field the browser sends), track tokens or cost per user, cap each user per day and per month with lower caps for free or anonymous accounts, cap input size and output tokens per request, and limit how many agent steps one request can trigger. An LLM gateway such as LiteLLM can enforce per-customer budgets for you. Keep the provider's project cap on as the last backstop, set below what you can afford to lose.
What should I check, step by step?
1. Key every LLM call to an end-user id your server sets from the logged-in session or API key. Never trust a user id the client sends; anyone can send a new one per request and get a fresh budget each time.
- Track spend per user from the provider's usage numbers (input and output tokens per call) times your model prices, and keep the running totals where the user and the agent can't change them.
- Set a daily and a monthly cap per user, lower for free trials and anonymous visitors, and refuse further calls with a clear message when a user hits it. Don't let the refusal fall through to a retry loop.
- Cap request size before it reaches the model: maximum input characters or tokens, maximum file size, and a max output token setting on every call.
- Limit agent work per request: maximum tool calls or steps, a wall-clock timeout, and a cap on parallel requests per user. One chat message shouldn't be able to start an unbounded loop.
- Add rate limits per user and per IP or device, plus signup friction for free tiers (verified email, payment method or CAPTCHA), so one person can't open many accounts to multiply the free budget.
- Alert on outliers: a user whose spend jumps far above their usual, or above the median for their plan, before they reach the cap.
- Keep a hard spend limit on the provider project or workspace as the backstop, and put free-tier traffic in its own project or workspace so abuse there can't take paying users down with it.
Why don't OpenAI or Anthropic spend limits stop one user from running up my bill?
OpenAI's spend limits guide says hard limits can be set for the organization or a project and are monthly; when tracked spend reaches one, affected requests return a 429 with organization_spend_limit_exceeded or project_spend_limit_exceeded, and enforcement is not instantaneous, so recorded spend can slightly exceed the cap. Anthropic's rate limits docs let you set a spend limit below your tier's cap (not on the default workspace), after which requests return HTTP 400 invalid_request_error.
- Both are per account, project or workspace, not per end user. If every customer's chat goes through one project key, a single abuser can exhaust the month's budget for everyone. That's the outage version of the problem; the bill version is just as real when no cap is set at all.
- OWASP's Top 10 for LLM Applications entry LLM10:2025 Unbounded Consumption describes Denial of Wallet as initiating a high volume of operations to exploit the cost-per-use model of cloud AI services. Its listed mitigations include input validation with size limits, rate limiting and user quotas, managing resource allocation so no single user or request consumes too much, timeouts and throttling, limits on queued and total actions, and logging and anomaly detection.
How do I set a per-user budget for LLM calls with a gateway like LiteLLM?
LiteLLM's proxy can track spend and enforce budgets per customer (end user). It reads the customer id from headers such as x-litellm-end-user-id or x-litellm-customer-id, or from the user field in the request body. A customer can be given max_budget, budget_duration, rpm_limit, tpm_limit and max_parallel_requests, and a default budget set with max_end_user_budget_id applies to every customer without one of their own, including customers it hasn't seen yet. In the docs' example, the next call after a customer goes over budget is rejected with an error that shows the spend and the budget.
- Two details matter. LiteLLM's docs say customer budgets are global per deployment: spend is tracked against the customer id alone, across every key and team. And the id comes from the request unless you use JWT auth with end_user_id_jwt_field, where the verified token's claim takes precedence. So set the header on your server after authenticating the user; if your browser code calls the gateway directly with a user id it chose, the budget is easy to dodge.
- Whatever tool you use, the same pattern applies: identify the user server-side, meter every call, and check the user's remaining budget before the call, not after the invoice.
How do I ask Rightshold about this (free, no key)?
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Before my support agent calls a paid data API for a customer, check the $0.25 call against that agent's spending policy and tell me whether to proceed.”
{
"tool": "authorize_spend",
"arguments": {
"credential_id": "<support agent's credential id>",
"amount_minor": 25,
"currency": "USD",
"merchant_domain": "api.example-data.com",
"category": "data_api",
"reference": "<your request id>"
}
}- Set the policy first with set_spend_policy (owner account key): per_tx_max_minor, daily_max_minor and allowed_domains for the agent's credential. Each allow counts toward the day's total, which resets at 00:00 UTC.
- authorize_spend returns a signed allow or deny receipt (for example over_daily_cap) and records it on Rightshold's ledger, so you can show later which paid calls were checked.
- Per-end-user token budgets for your LLM calls belong in your app or gateway; use Rightshold for the agent's paid actions beyond the model call.
Rightshold checks proposed paid actions against the policy you set for an agent's credential and records signed decisions. It doesn't sit in your LLM traffic, count tokens, identify your end users or enforce per-user quotas, and it never holds or moves money. Not financial or security advice.
What are the sources?
- OWASP Gen AI Security Project: LLM10:2025 Unbounded Consumption (Denial of Wallet)
- OpenAI API docs: Spend limits
- Claude docs: Rate limits (setting your own spend limit)
- LiteLLM docs: Customers / End-Users (customer id headers, JWT precedence, default budget)
- LiteLLM docs: Budgets, Rate Limits (customer budgets are global per deployment, budget_duration)
Related
- Giving each AI agent its own budget for paid APIs
- Seeing how much each AI agent spends on LLM API calls
- Stopping an AI agent from looping forever and burning tokens
- Rate limiting an AI agent's API calls per key
Not legal advice. JSON · Markdown · All answers
Get a free API key in one call
No card and no email needed. 100 free credits; the license and policy checks stay free without a key.
curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_... # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
-H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'
