Assume a $29 monthly SaaS plan spends $5.25 on one customer's AI usage: that leaves $23.75 before other costs. To control that spend, authenticate each customer, create a capped gateway key, keep it server-side, tag end users and record usage in your billing ledger. We make Requesty, one of the gateways compared below.
What a customer key controls
A gateway key is a bearer secret used to call a gateway. Give each customer account, also called a tenant, its own key to attribute model spend and set a limit. The SaaS backend holds the key, even if the customer has a separate credential for your own API.
| Credential | Who holds it | What it does |
|---|---|---|
| SaaS API key | Your customer | Authenticates access to your product |
| Gateway key | Your backend | Authenticates model requests and scopes gateway spend |
| Provider key | Your company or customer | Authenticates to a model provider and determines the provider billing account |
Letting customers bring their own provider keys is a separate product decision. With bring your own key, or BYOK, the customer supplies a provider credential and manages the provider billing relationship. Requesty's BYOK documentation specifies at most one key per provider in an organization. Separate customer-owned keys require separate organizations or your own tenant-scoped provider integration.
A key cap does nothing for another customer's database rows, documents, cached data or logs. Apply tenant authorization across those resources. AWS's SaaS isolation guidance defines isolation as preventing one tenant from accessing another tenant's resources.
Design the tenant flow
The server derives the tenant from authenticated membership. It then looks up that tenant's gateway key in a secret store and checks the customer's plan before sending a request. Reject a missing mapping; never fall back to a shared production key. A browser-supplied tenant ID or request tag is not proof of membership.

Add a pseudonymous end-user ID and feature name to requests for attribution within the tenant. Those fields describe usage; they do not authorize a request or impose an end-user budget. Limit access to logs and follow your privacy policy for identifiers. Requesty's observability page shows how request metadata breaks down spend.
A separate key also does not reserve any capacity. Requesty's in-flight limit is shared across organization keys, and a prepaid organization shares a balance. Use tenant-scoped queues and fair scheduling in your application so a batch job from one customer does not occupy all available slots.
Create a capped customer key in Requesty
Requesty gives each customer key its own monthly cap and records usage across providers. As of October 2026, automate creation with the Enterprise Key Management API using a management key with read and write permissions. Keep that key in your backend, separate from customer traffic keys.
For manual setup, open API Keys, create or edit a key, and set its monthly spend limit, as described in per-key limits. For prepaid billing, add credits before testing or using a paid model. Postpaid billing is available by agreement. The examples use a fictional Acme tenant and USD amounts.
- 1Create the key at signup
Use the create-key endpoint to give Acme a $25 monthly cap and completion permission without management permission. Set
REQUESTY_MANAGEMENT_KEYin your server environment. This shell example saves the response to a fresh private temporary file; production provisioning should write the secret directly to a secret manager.Shellumask 077 KEY_RESPONSE_FILE=$(mktemp "${TMPDIR:-/tmp}/requesty-tenant-key.XXXXXXXX") curl --fail-with-body -sS https://api-v2.requesty.ai/v1/manage/apikey \ -H "Authorization: Bearer $REQUESTY_MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "tenant-acme-prod-op-7f83c1d2", "monthly_limit": 25, "permissions": {"manage": "none", "completions": "write"} }' -o "$KEY_RESPONSE_FILE"The response contains
api_key_idand the secretapi_key. The secret is returned once. Store it securely, persist the tenant-to-key-ID mapping, and delete the temporary file after transferring it. Do not log the response.Guard signup against provisioning the same tenant twice. Generate and persist a different operation suffix for each provisioning operation; use it to investigate an ambiguous creation before starting a replacement operation. After a timeout, use the key list to investigate matching keys. Delete a confirmed orphan whose secret was not saved before issuing a replacement; account for a creation request that may still be in flight.
- 2Label the key and set an expiry
Set
KEY_IDto the returned UUID, not the secret. Labels are a separate update; expiry is another update. Use your own tenant ID and expiry date.Shellcurl --fail-with-body -sS -X POST \ "https://api-v2.requesty.ai/v1/manage/apikey/$KEY_ID/label" \ -H "Authorization: Bearer $REQUESTY_MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{"labels":{"tenant_id":"tenant_acme","plan":"pro"}}' curl --fail-with-body -sS -X POST \ "https://api-v2.requesty.ai/v1/manage/apikey/$KEY_ID/expiry" \ -H "Authorization: Bearer $REQUESTY_MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{"expires_at":"2027-01-31T23:59:59Z"}'Both updates return
204on success. An empty label object removes labels. Before a scheduled expiry has passed, sending a JSON body withexpires_atomitted or null removes it. The expiry endpoint cannot update a key after it has expired.If the tenant needs model restrictions, attach its access list in the API Keys console. Test allowed and denied models before enabling tenant access. Record paid prelaunch test usage as internal usage in the ledger, so it is not billed to the customer; it still counts toward the key's spend. Requesty's governance page explains the organization and key policy layers.
- 3Send a request for an authenticated user
Install the
openaiPython package. For this example, setREQUESTY_TENANT_KEYto the Acme key. In production, resolve it from the secret store after checking membership. The metadata guide documentsuser_id,trace_idandextra; the model library listsopenai/gpt-6.1-terra.Pythonimport os from openai import OpenAI client = OpenAI( api_key=os.environ["REQUESTY_TENANT_KEY"], base_url="https://router.requesty.ai/v1", max_retries=0, ) response = client.chat.completions.create( model="openai/gpt-6.1-terra", messages=[{"role": "user", "content": "Summarize this ticket."}], extra_body={"requesty": { "user_id": "user_123", "trace_id": "session_456", "extra": {"feature": "ticket_summary"}, }}, ) print(response.choices[0].message.content) print(response.usage.model_dump().get("cost"))Requesty returns
usage.costin USD for non-streaming chat completions. Record it in your ledger and reconcile it against gateway and provider billing before invoicing.
Keep budgets correct as keys change
Alerts and customer-facing errors
Configure API Key % of Budget alerts at, for example, 50%, 80% and 95%. In Admin Panel > Alerts, add a valid webhook first: Requesty's alert documentation says notifications are not sent without one. The JSON event includes an event id, key ID and spend. Deduplicate deliveries by event ID and use them for warnings, not as invoice line items. See Requesty spend management for the available budget scopes.
When the cap is reached, Requesty blocks new requests for that key until the next billing period. The router returns HTTP 412 with the message This API key, user or group has reached its monthly spend limit. An admin can raise the limit in the Requesty dashboard. Tell the customer to wait or upgrade; do not retry indefinitely. An organization balance exhaustion is a separate 402, while 429 can indicate in-flight or provider rate pressure. Inspect the origin and message before deciding whether to retry; the error reference describes these categories.
Your customer's billing period and the gateway's monthly period rarely line up. A contract period might start on a customer's signup anniversary. Store the contract start, end, included credits and overage policy in your ledger. Confirm the gateway reset timing for your account before promising a date to customers.
Concurrent requests need a reservation
Suppose a customer's remaining entitlement is $0.40 and two requests can each cost up to $0.30. If both check the same $0.40 before either settles, both can be admitted, leaving $0.60 of exposure. An alert does not reserve the remaining entitlement.
For a strict application entitlement, atomically reserve a conservative maximum against shared tenant state before dispatch. Bound input, maximum output, modalities, retries and fallback model prices in the estimate. After completion, settle actual usage and release the unused reservation. Give each reservation a durable ID so your ledger does not record the same charge twice.
The OpenAI SDK retries some failures by default, so the example disables its automatic retries. Control retries in your application, reserve for each possible billable attempt, and reconcile an attempt with an unknown outcome before releasing its reservation. Account for retries and fallbacks configured in the gateway. A duplicate ledger entry and a second billable inference are different problems.
For streaming, request stream_options: {"include_usage": true}. Requesty's streaming documentation places usage in the final chunk, which the client may miss after a disconnect. Reconcile missing chunks against gateway records and billing; preserve the reservation until the cost is resolved.
Upgrade, rotate and expire
To increase a cap after an upgrade, call the limit endpoint with the key UUID:
curl --fail-with-body -sS -X POST \
"https://api-v2.requesty.ai/v1/manage/apikey/$KEY_ID/limit" \
-H "Authorization: Bearer $REQUESTY_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{"monthly_limit":50}'Update the customer's entitlement in your ledger as part of the upgrade. Do not set the Requesty key limit to zero to pause a customer: the key reference defines zero as unlimited. Disable access in your application and expire or delete the key instead.

Now, the not so great news: the replacement has its own counter. For rotation, create a replacement and store its secret. If the old key has an attached access list, attach the same list to the replacement in the console. Verify its effective model policy with allowed and denied requests before switching the tenant mapping. Enforce the shared entitlement during overlap and switch new traffic to the replacement key.
For a planned rotation, drain and reconcile the old key's in-flight requests, record its usage and label mapping, and preserve both key IDs in your tenant history before deleting the old key. If a key is compromised, delete it immediately and reconcile outstanding usage from your application records and available gateway data.
To revoke the old key, set KEY_ID to its UUID and call delete:
curl --fail-with-body -sS -X DELETE \
"https://api-v2.requesty.ai/v1/manage/apikey/$KEY_ID" \
-H "Authorization: Bearer $REQUESTY_MANAGEMENT_KEY"Deletion is permanent: every later request with that key fails. Test in-flight traffic and the cutover before rotating a production tenant.
Turn customer usage into an invoice
A spend cap limits access. It does not work out your SaaS bill for you. Your ledger needs a usage record for each request or billing event, including tenant ID, gateway key ID, request ID, timestamp, model and provider, cost, price version and entitlement period. Store corrections as separate entries so you can explain an invoice later.
Use Requesty's organization usage endpoint to reconcile totals by api_key_id, user_id, extra.feature or api_key_label.tenant_id. Group by both api_key_id and user_id to distinguish users within each tenant; use tenant-scoped or globally unique user IDs, and roll historical key IDs into the tenant's ledger after rotation. The endpoint supports repeated group_by fields and date ranges of up to 100 days. Missing labels appear under Unknown; investigate that bucket before billing.
For the customer dashboard, authorize the tenant on the server and return that tenant's entitlement period, included credits, settled usage and remaining credits from your ledger. Show Requesty key spend separately as an operational metric. The key endpoint provides monthly_spend and monthly_limit, but those fields do not automatically equal the customer's remaining credit balance.
Define what a credit buys and publish the conversion for each model or feature. Deduct credits from the customer's entitlement ledger as usage settles. If models have different costs, use a model-specific conversion or accept that equal credit usage has different margins.
Work out the billable amount as measured cost plus your stated markup. Include the allocated gateway fee and any other agreed charges once. Keep your price version and rounding rules with each ledger entry.
Send billable units to Stripe
Assume a plan includes 1,000 credits per entitlement period and charges overage through a separate metered price. If a customer consumes 1,025 credits, deduct the included 1,000 in your ledger and send 25 billable overage credits to the meter. Do not send included credits to that overage meter. Align pricing and entitlement periods with the customer contract.
Configure a raw-event Stripe meter with event name ai_credits, sum aggregation and the default stripe_customer_id and value payload mappings. Attach the meter to a recurring metered price, add that price to the customer's subscription, and map your tenant to the Stripe customer. See Stripe's usage-based billing implementation guide and meter configuration.
For new usage-based billing integrations, Stripe recommends Metronome. Billing Meters remains available; this example uses its API to send the 25 overage credits:
curl --fail-with-body -sS https://api.stripe.com/v1/billing/meter_events \
-u "$STRIPE_SECRET_KEY:" \
-H "Idempotency-Key: usage_event_123" \
-d "event_name=ai_credits" \
-d "payload[stripe_customer_id]=$STRIPE_CUSTOMER_ID" \
-d "payload[value]=25" \
-d "identifier=usage_event_123" \
-d "timestamp=$USAGE_UNIX_TIMESTAMP"Replace usage_event_123 with a unique stable ID for each ledger event. Set USAGE_UNIX_TIMESTAMP to the original event time in seconds since the Unix epoch; keep the ID, timestamp and other parameters unchanged on retries. Stripe's meter-event reference describes these fields.
Write the usage entry and an outbox entry in the same database transaction. Keep a durable local deduplication record. For an ambiguous network delivery, retry with the same identifier, idempotency key and parameters within the first 24 hours. After that, stop automatic retries and reconcile the outcome with Stripe; contact Stripe support if it remains unclear before resending. A 500 can also have an indeterminate outcome. Stripe's API v1 error guidance explains the retry window.
Inspect the original request in Stripe Workbench Logs and check meter processing errors. Meter summaries are aggregates, so they do not prove whether one event identifier was recorded.
Serialize v1 meter-event submissions per customer and meter, or batch usage when volume requires it: Stripe permits one concurrent call per customer per meter. For a batch, retain the original ledger event IDs and timestamps, assign the batch its own stable identifier, and keep its usage within the correct billing period.
Stripe processes meter events asynchronously, so its summaries are unsuitable for synchronous budget admission. Monitor asynchronous meter errors and compare meter totals with your ledger. When reconciliation needs more time, configure an invoice finalization grace period for eligible invoices. Threshold invoices have different cutoffs, and mid-cycle price changes can prevent late usage from being captured during the grace period.
Stripe accepts event timestamps within the past 35 calendar days and up to 5 minutes in the future. An event accepted after invoice finalization is not guaranteed to appear on that invoice or the next. Reconcile the ledger, gateway usage, provider or gateway charges, and meter events before finalization; use a documented adjustment process for late corrections.
Check the plan economics
Assume two hypothetical SaaS plans and an Enterprise agreement using Requesty's standard prepaid billing terms. Enterprise pricing is custom, so use your contracted fee for the same calculation. On standard prepaid terms, Requesty adds a 5% fee on top of credit top-ups: a $100 top-up costs $105 and credits $100. Allocate that fee proportionally to credits consumed by each tenant. The table excludes taxes, discounts and all non-model costs.
| SaaS plan | Monthly revenue | Provider consumption | Allocated top-up fee | Revenue less AI cost | Revenue less AI cost, % of plan |
|---|---|---|---|---|---|
| Starter | $29 | $5 | $0.25 | $23.75 | 81.90% |
| Pro | $99 | $20 | $1 | $78 | 78.79% |
For Starter, $5 x 5% = $0.25, so ($29 - $5.25) / $29 = 81.90%. For Pro, ($99 - $21) / $99 = 78.79%. The fee is charged at top-up; allocating it to consumed credits is an accounting assumption. Count it once. These are AI-cost contributions, not total company gross margins. The customer entitlement and the gateway cap are separate settings.
Now consider a cost-plus customer with $10.50 in AI costs. A 30% markup gives $10.50 x 1.30 = $13.65, or ($13.65 - $10.50) / $13.65 = 23.08% margin. To earn a 30% margin on those costs, charge $10.50 / 0.70 = $15. If usage doubles while plan revenue stays fixed, recalculate the contribution before promising unlimited AI features.
Requesty, LiteLLM or Portkey?
The right choice depends on who will run the gateway and which limits the SaaS needs. The table reflects vendor documentation checked in October 2026.
| Product | Tenant budget approach | Pick it when | Condition to check |
|---|---|---|---|
| Requesty | Monthly cap per key, with key alerts and usage metadata | You want managed multi-provider access and Enterprise key automation | Key Management API requires Enterprise; in-flight capacity is shared across the organization |
| LiteLLM | Per-key and shared team budgets, plus per-key RPM and TPM limits | You want an open-source proxy you can self-host | Budgets require a database; team-owned keys do not enforce the owner's personal budget |
| Portkey | Key and workspace budgets with request and token limits | You need workspace controls or metadata-keyed customer policies | Metadata-based usage policies require Enterprise Self Hosting and gateway 1.17.0 or later |
LiteLLM also documents a hosted proxy option. Its budget reservation is enabled by default for priceable requests; an optional fail-closed budget setting checks spending against the database. LiteLLM's docs say some image and audio routes and batch jobs cannot be fully reserved. Test the paths and deployment you intend to use.
On Enterprise Self Hosting, Portkey can group a usage policy by customer metadata, creating separate counters without a key per customer. Its fine-grained policy threshold events go to audit logs; proactive notifications for those policy thresholds are listed as work in progress.
LiteLLM also supports customer budgets keyed by the request's user field, without issuing a key for each customer. Its customer budget is global to the deployment across keys and teams, so use unique customer IDs. Set the field from authenticated tenant membership in your backend.
A shared tenant budget across keys measures their combined spend; independent key caps give each key its own allowance. Match the scope and reset window to the customer contract. Test each deployment under parallel traffic before committing to a strict spend guarantee.
Before your first customer goes live
Multi-tenant LLM launch checklist
0 of 9 done
Pick Requesty for managed per-key caps across providers, LiteLLM for self-hosted virtual keys, and Portkey if you already use Palo Alto's stack and want its workspace controls. This week, run one tenant from signup through a test invoice. For Requesty, sign up and use the Enterprise Key Management API to automate provisioning.
Frequently asked questions
- How do I give each SaaS customer an LLM API key and budget?
- Authenticate the customer in your backend, create a gateway key for that tenant, set a monthly spend limit, and store the secret server-side. Requesty's Enterprise Key Management API supports automated key creation and limit updates.
- Is a per-customer gateway key the same as a customer-owned provider key?
- No. A gateway key controls access to the gateway; a customer-owned provider key is issued by a model provider and billed under the customer's provider account. Requesty's BYOK documentation specifies at most one key per provider in an organization.
- How do I track LLM usage for each customer and user?
- Use a separate gateway key for each customer and attach a pseudonymous end-user ID to each request. Requesty reports cost by API key and request metadata, while your application authenticates users and maintains the tenant mapping.
- What happens when a customer reaches a Requesty API key budget?
- Requesty blocks new requests on the key until the next billing period when its spend limit is reached. The gateway returns HTTP 412 with the message 'This API key, user or group has reached its monthly spend limit. An admin can raise the limit in the Requesty dashboard'. Show an upgrade or wait message instead of retrying indefinitely.
- How do I bill customers for LM usage?
- Record tenant usage in your own ledger, apply the customer's credit or cost-plus pricing rules, and send billable units to a billing service such as Stripe. Reconcile usage and corrections before finalizing invoices.
- Which is better for tenant budgets: Requesty, LiteLLM or Portkey?
- Pick Requesty for managed per-key caps and Enterprise API automation. Pick LiteLLM for an open-source proxy you can self-host; pick Portkey for workspace controls or metadata-keyed policies, with the latter on Enterprise Self Hosting.
- Can concurrent LLM requests exceed a customer budget?
- Parallel requests and delayed settlement create exposure near a budget boundary. An application can reserve a conservative maximum cost atomically before dispatch, including every billable retry and fallback, then settle the actual usage.
- SEP '26
429 Too Many Requests: Causes and Fixes for LLM APIs
Fix 429 too many requests errors with provider-specific headers, billing checks, Retry-After parsing, bounded Python and TypeScript retries, and fallbacks.
- SEP '26
The same benchmark suite costs $0.05 on one model and $3.69 on another: stop comparing price per token
Artificial Analysis publishes the measured cost of running its evaluation suite on each model. On the 2026-09-03 snapshot the spread is 76x, and the ranking does not match the per token price list.
- SEP '26
OpenAI-Compatible APIs: Meaning, Providers and Examples
An OpenAI compatible API lets you reuse your SDK, but features vary. Compare provider endpoints, tools, streaming, JSON, vision and Responses support.
