Setting Spend Limits and Usage Caps per API Key
Per-key credit limits are hard stops on how much a single API key can spend before OpenRouter returns 402 Payment Required.
They contain blast radius when an agent loops, a leaked key runs hot, or a tenant goes over plan.
Summary
Create or update inference keys with a limit (and optional limit_reset), monitor limit_remaining via GET /api/v1/key, and isolate each agent environment or customer on its own key.
Recipe
- Create a Management API key at OpenRouter Settings → Management Keys (management keys cannot call chat completions).
- Inventory callers: local dev, CI, staging agent, production agent, per-tenant SaaS keys.
- For each caller, choose a dollar credit
limitand reset policy (daily,weekly,monthly, or no reset - verify allowed values at build). - Create or patch keys through
POST/PATCH /api/v1/keyswithlimit,limit_reset, and optionalinclude_byok_in_limit. - Store only inference key secrets in your secret manager; never commit them.
- Before heavy jobs, call
GET /api/v1/keywith the inference key and abort iflimit_remainingis too low. - On 402, alert, pause the agent, and decide whether to raise the cap or fix the loop.
- Rotate or disable keys (
disabled: true) when a limit is hit unexpectedly.
Working Example
import os
import requests
MGMT = os.environ["OPENROUTER_MANAGEMENT_KEY"]
BASE = "https://openrouter.ai/api/v1/keys"
H = {
"Authorization": f"Bearer {MGMT}",
"Content-Type": "application/json",
}
# 1) Create a capped production key
created = requests.post(
f"{BASE}/",
headers=H,
json={
"name": "agent-prod",
"limit": 100.0,
"limit_reset": "monthly",
"include_byok_in_limit": False,
},
)
created.raise_for_status()
body = created.json()
# Secret is shown on create; persist it immediately
print("hash:", body.get("data", body).get("hash") if isinstance(body, dict) else body)
# 2) List keys (paginate with offset)
listed = requests.get(BASE, headers=H, params={"offset": 0})
listed.raise_for_status()
print("keys:", listed.json())
# 3) Inference side: check remaining quota
inf = os.environ["OPENROUTER_API_KEY"]
key_info = requests.get(
"https://openrouter.ai/api/v1/key",
headers={"Authorization": f"Bearer {inf}"},
)
key_info.raise_for_status()
data = key_info.json()["data"]
remaining = data.get("limit_remaining")
if remaining is not None and remaining < 1.0:
raise SystemExit(f"insufficient key budget: {remaining}")
print(
"usage_daily=", data.get("usage_daily"),
"usage_monthly=", data.get("usage_monthly"),
"limit_remaining=", remaining,
)Update an existing key by hash:
key_hash = "<YOUR_KEY_HASH>"
patched = requests.patch(
f"{BASE}/{key_hash}",
headers=H,
json={
"limit": 150.0,
"limit_reset": "daily",
"disabled": False,
},
)
patched.raise_for_status()Deep Dive
Two budgets you must not confuse
| Budget | Scope | Failure mode |
|---|---|---|
| Account credits | Whole OpenRouter balance | All keys fail when empty |
Per-key limit | One inference key | That key returns 402; others continue |
Raising a key limit never creates money. You still need account credits.
Response fields that matter
From GET /api/v1/key (inference key):
limit- cap ornullif unlimitedlimit_remaining- residual budgetlimit_reset- reset cadence ornullusage,usage_daily,usage_weekly,usage_monthlybyok_usage*andinclude_byok_in_limitwhen using provider keys through OpenRouter
Use daily/weekly fields for anomaly detection even when the hard cap is monthly.
Agent design with caps
- Separate keys per autonomy level. Read-only research agent gets a higher cap than a write-enabled ops agent.
- Fail soft on 402. Surface "budget exhausted" to the user or queue; do not tight-loop retries.
- Pair with max turns. Key caps are last-resort; application max steps stop damage earlier.
- SaaS isolation. One key (or workspace budget, if you use workspaces) per customer plan tier.
Workspace and guardrail budgets
Organizations can also use workspace budgets and guardrails for spend and model access (see OpenRouter workspaces/guardrails docs at build).
Per-key limits remain the simplest unit for single-service agents.
Gotchas
- Management key ≠ inference key. Chat calls with a management key fail; analytics/key admin with only an inference key may 403.
- Unlimited keys (
limit: null) are footguns in production agents. Prefer an explicit number. - Reset timezone is UTC. Daily resets at midnight UTC can surprise local-business-day dashboards.
- BYOK accounting. Decide whether external provider spend counts toward the OpenRouter key limit via
include_byok_in_limit. - 402 vs 429. Out of credits/limit is 402; rate limits are 429. Retry logic must not treat them the same.
- Create response is the only time you see the full secret. Hash/label fields are not the raw key.
- CI keys need tiny caps. Eval suites should fail closed, not burn production budget.
Alternatives
| Control | Granularity | Enforcement |
|---|---|---|
| Per-key credit limit | Key | OpenRouter 402 |
| Account balance only | Account | OpenRouter 402 |
| Application dollar budget | Run / tenant | Your code |
| Workspace budgets | Team/project | OpenRouter (org feature) |
| Provider console limits | Direct API | Provider-specific |
FAQs
What currency is limit?
Limits are in OpenRouter credits denominated like USD for pricing purposes. Confirm exact units in the live key API response at build.
Can I raise a limit automatically when it hits zero?
Yes via the Management API, but do it behind alerts and approval. Auto-raising without a human can fund infinite loops.
Do free model calls count against the key limit?
Free variants have separate rate limits. Paid usage decrements credits and key limits. Verify free-tier interaction for your account type at build.
How do I disable a compromised key?
PATCH /api/v1/keys/{hash} with {"disabled": true} using the management key, then rotate a replacement.
Is there a UI path without the Management API?
Yes. You can set credit limits when creating or editing keys in the OpenRouter keys UI. The API is for automation.
Should every developer share one key?
No. Shared keys hide owners and make limits meaningless. Issue per-dev keys with small daily caps.
What happens mid-stream when the budget dies?
Budget checks apply to request acceptance. Still design agents to checkpoint state so a later turn 402 can resume after funding.
Can limits reset on a custom calendar?
Documented reset helpers are fixed cadences such as daily/weekly/monthly. For custom periods, automate PATCH from your own scheduler.
Related
Related: Cost & Fallback Basics
Related: Monitoring OpenRouter Spend and Usage in Real Time
Related: Cost-Based Routing: Sending Cheap Tasks to Cheap Models
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.