LLM API key management for teams: keys are budget lines, not passwords
Updated 2026-07-15
Issue one key per service, per environment, inject it from a secret manager instead of code, and give every key a named owner and a monthly spend cap. Managed this way, each key becomes a unit of attribution and blast radius: any bill spike or leak traces to exactly one service in one environment, and revoking it breaks nothing else.
Quick answer: stop sharing, start mapping.
Most LLM key problems disappear after one decision: stop treating a provider key as a team-wide password and start treating it as a billing and attribution unit. The production chat assistant gets its own key. The staging copy of the same service gets a different one. The nightly summarization job gets a third. Nobody calls production with a key that also lives on a laptop. Three properties fall out of that mapping. Attribution: the provider's usage dashboard becomes readable, because every line corresponds to one service you can name. Blast radius: a leaked staging key cannot burn the production budget, and revoking it takes down nothing a customer can see. Rotation: replacing a key means one secret update and one deploy, not a coordinated freeze across every team that ever pasted the old value somewhere. The rest of this page works through what a key actually controls, a worked per-key budget for a small product team, the failure modes that make key management urgent at the worst possible time, a comparison of the common setups, and a code pattern that makes rotation boring.
What a key actually controls: identity, spend, and scope.
The practical consequence is that key granularity sets a hard ceiling on how much you can ever know about your own spend. If the invoice doubles and everything shares one key, the investigation starts with grepping application logs and correlating timestamps. If each service owns a key, the same investigation is thirty seconds in a dashboard. Spend caps deserve special attention because LLM traffic fails differently from most infrastructure. A bug that turns one retry into an infinite loop does not throw errors; it quietly buys tokens all night. A per-key cap sized a bit above expected spend converts that incident from an invoice problem into a paging problem, which is the kind you can actually fix at 2 a.m.
- The key is the billing identity. Every token in a request and response is billed to whichever key sent the call, no matter which human or service was behind it.
- The key is the attribution floor. Providers report usage per key or per project. Five services behind one key show up as one undifferentiated number.
- The key is the blast radius. Revocation is instant and total for everything that uses it, which is exactly what you want when it maps to one service and exactly what hurts when it maps to ten.
- Keys can usually be scoped. Most major providers now support project or workspace scoping with independent spend limits, so a cap on one key cannot be consumed by another team.
- A key is not a user identity. Your internal notion of user, feature, or tenant is invisible to the provider unless you segment by key or log token usage yourself.
A worked key map: four keys, one readable bill.
Here is what the mapping looks like for a small product team running four workloads: a customer-facing chat assistant on a frontier model, a document extraction pipeline, a high-volume intent classifier, and a shared staging plus CI environment. The token volumes are illustrative round numbers; the point is the shape, not the exact figures. Each row is one key with one owner and one cap. When the bill moves month over month, the per-key view says which line moved, and the key name says who to ask. The chat assistant dominates spend despite having the smallest token volume, which is typical: routing everything through the flagship model because it is the default is the single most common silent overspend in production LLM systems.
| Key / service | Model (list $/1M in / out) | Monthly tokens (in / out) | Monthly cost |
|---|---|---|---|
| prod-chat-assistant | claude-sonnet-4-6 ($3 / $15) | 120M / 8M | $480.00 |
| prod-doc-extraction | deepseek-v4-pro ($0.435 / $0.87) | 300M / 30M | $156.60 |
| prod-intent-classifier | deepseek-v4-flash ($0.14 / $0.28) | 500M / 20M | $75.60 |
| staging-and-ci | gpt-5.4-mini ($0.75 / $4.50) | 40M / 4M | $48.00 |
Why key management blows up at the worst possible moment.
The common thread is coupling. Every incident on this list is survivable when a key maps to exactly one service in one environment: you revoke it, redeploy one thing, and write the postmortem. The same incidents are company-wide emergencies when one key is load-bearing for everything. Note that none of these failures are exotic. They are the default outcome of the way most teams start, which is one key created on day one, pasted wherever it was needed, and never looked at again.
- The shared key committed to a .env file once, years deep in git history. Automated scanners watch public repositories continuously, and abuse of a leaked key typically starts before anyone on the team notices the leak.
- Zero attribution. One key across five services means the answer to "why did the bill double" begins with log archaeology instead of a dashboard filter.
- Rotation needs a coordinated redeploy of everything, so it never happens, so the key issued by an engineer who left two years ago still authenticates production.
- Personal keys in production. Someone ships a prototype under their own account, the prototype becomes a product, the person leaves, and a revenue-bearing service quietly loses auth when their account closes.
- Cap exhaustion cascades. A retry storm in a background job drains the shared quota and takes the customer-facing feature down with it, turning a batch bug into a user-visible outage.
- Keys leak into places that outlive the moment: CI logs, error tracker payloads, support screenshots, and prompts pasted into chat tools.
Four ways teams run keys, compared.
These are the setups that actually occur in the wild, ordered roughly by maturity. Most teams should aim for the third or fourth row; the second is a reasonable waypoint that already eliminates the worst failure modes.
| Approach | Attribution | Leak blast radius | Rotation cost | Fits |
|---|---|---|---|---|
| One shared key in config | None: one line for the whole org | Everything, every environment | Coordinated redeploy of all services | Solo prototypes only |
| Per-service keys in env vars | Per service | One service | One secret update, one deploy | Small teams shipping fast |
| Per-service plus per-developer keys | Per service and per person | One service or one laptop | Same, plus scheduled dev-key expiry | Teams of roughly 5 to 50 engineers |
| Secret manager, scoped keys, per-key caps | Per service, enforced by caps | One service, bounded in dollars | Near zero with overlap rotation | Anything customer-facing |
Seven fixes that pay for themselves.
On the last point, one gateway option is APIsRouter: an OpenAI-compatible API with pay-as-you-go billing and no subscription, where global models are priced 20% below official list, Chinese models sit below their official rates, and the first top-up adds +100% balance. Keys come from a checkout that takes payment first and emails the key, with no signup, which makes minting a separate low-value key per service or per experiment a two-minute task rather than a procurement ticket. Consolidation also simplifies the budget ladder itself, because every tier of the key map bills through the same surface at the same key format:
- Inventory first. List every place a provider key currently lives: env files, CI variables, notebooks, dashboards, old scripts. You cannot scope what you cannot find.
- Issue per-service, per-environment keys and name them like infrastructure: prod-chat-assistant, staging-doc-extraction. A key name should answer "what breaks if I revoke this".
- Put a monthly cap on every key or project, sized at two to three times expected spend, so a runaway loop hits a wall instead of the card.
- Move keys out of code and .env files into a secret manager or your platform's encrypted variables, and grant each service read access to exactly one secret.
- Rotate with an overlap window: issue the new key, deploy, verify traffic has moved, then revoke the old one. Rotation stops being scary the first time it takes ten minutes.
- Alert on per-key anomalies, not just account totals. A key whose daily spend doubles is either a bug or a leak, and both are far cheaper caught on day one.
- Consolidate long-tail providers behind one OpenAI-compatible endpoint, so you manage one key format, one billing surface, and one revocation path instead of a console per vendor.
| Model ID | Input $/1M | Output $/1M | Slot in the key map |
|---|---|---|---|
| claude-sonnet-4-6 | $2.40 | $12.00 | Customer-facing chat |
| gpt-5.4-mini | $0.60 | $3.60 | Staging and CI |
| glm-5 | $0.514 | $2.314 | Agentic sub-tasks |
| deepseek-v4-pro | $0.3915 | $0.783 | Extraction, summarization |
| deepseek-v4-flash | $0.126 | $0.252 | Classification, routing |
A key-handling pattern that survives rotation.
The pattern below is deliberately boring. The service reads its key from the environment at startup, the environment is populated by the secret manager at deploy time, and no key string ever appears in the repository, the image, or the logs. Because the key arrives through one env var, rotation is a secret update plus a redeploy, and nothing in application code changes. Before flipping traffic to a freshly issued key, verify it out of band. A ten-second curl against the chat completions endpoint proves the key, the base URL, and the model ID in one shot, which turns the rotation checklist into: issue, verify, deploy, watch the dashboard, revoke.
import os
from openai import OpenAI
def llm_client() -> OpenAI:
api_key = os.environ["LLM_API_KEY"] # injected by the secret manager
return OpenAI(
base_url="https://api.apisrouter.com/v1",
api_key=api_key,
)
resp = llm_client().chat.completions.create(
model="deepseek-v4-pro",
messages=[{"role": "user", "content": "healthcheck"}],
max_tokens=8,
)
print(resp.choices[0].message.content)FAQ
How many LLM API keys should a team have?
One per service per environment, plus short-lived personal keys for local development. A ten-service product with production and staging lands north of twenty keys, which sounds heavy until the day you need to revoke exactly one of them without touching the rest.
How do I rotate an LLM API key without downtime?
Use an overlap window. Issue the new key, verify it out of band with a curl request, update the secret and redeploy, confirm in the usage dashboard that traffic has moved to the new key, then revoke the old one. Both keys are valid during the window, so no request ever fails for auth.
What should we do the moment a key leaks?
Revoke it immediately rather than waiting to line up a replacement: a short outage beats an unbounded bill. Then audit the per-key usage log for calls you did not make, issue a replacement through the secret manager, and close the path it leaked through, which is usually a committed .env file or CI logs.
Should keys live in environment variables or a secret manager?
Both, in sequence: the secret manager is the source of truth, and an environment variable is the delivery mechanism at deploy time. What you are avoiding is keys in files that git can see, because a committed .env is how most real-world leaks start. Rotation then becomes a one-secret update.
How do we attribute LLM spend to teams or features?
Key granularity is your attribution floor. Per-service keys give you per-service spend straight from the provider dashboard with zero code. Attribution finer than that, per feature or per tenant, requires logging token counts from API responses against your own request metadata.
What is the cheapest way to give every service its own API key?
Pick billing with no per-seat or per-subscription overhead, so a marginal key costs nothing to hold. APIsRouter works this way: pay-as-you-go with no subscription, global models priced 20% below official list, Chinese models below their official rates, a first top-up that adds +100% balance, and a no-signup checkout at /topup that takes payment and emails the key in minutes.