The shape
- Each end-user has their own VK. One per customer, or per seat, your call.
- You set per-customer budgets. Enforced at the gateway. When a customer hits their cap, the gateway returns
402 budget_exceeded. Your code doesn’t need to track spend. - All audit + trace data lands in your LangWatch project. End-users never see LangWatch.
- End-users can’t escape your policy. Policy rules, model allowlists, cache rules all attach to the VK.
Step 1: Model the tenancy
Decide your scope granularity:
For this walkthrough, assume per-customer model. Note that
principal budgets target real LangWatch user accounts, which your external customers are not; for reseller tenancy the per-customer unit is the virtual key itself.
Step 2: Configure the upstream ModelProvider once
Your LangWatch org owns a single ModelProvider row per upstream (OpenAI, Anthropic) at ORGANIZATION scope. End-users never see these. Configure them under Settings → Model Providers → Add Model Provider (Scope = Organization), then open each row’s Advanced (Gateway) tab and set the per-credential gateway caps:
No separate “binding” entity to mint. The ModelProvider id is what your code references:
Step 3: Provision a VK with its cap when a customer signs up
One call mints the key AND its budget, atomically: the key can never exist for a moment without the cap you asked for. Server-side code (Node.js example):routing_policy_id plus routing_mode: "POLICY" if you run a custom ordering; otherwise leave routing at its default.
In a signup webhook:
Step 4: Change the cap when the plan changes
Thebudget field on update upserts the key’s own cap, so plan changes are one call keyed by the VK id you stored (no budget id bookkeeping):
budget: null to remove the cap entirely (the spend history stays). Changes propagate to the gateway within 30 s via the /changes feed, no restart, no customer impact.
Step 5: End-user makes a call
Your customer’s app calls the gateway directly with the VK you gave them:- Authenticates the VK.
- Checks the customer’s budget.
- Applies your
modelsAllowedallowlist. - Dispatches to OpenAI using your provider credential.
- Meters the cost against the customer’s budget.
- Emits a LangWatch trace into your project, attributed to the key.
Step 6: Show the customer their spend and bill them
The read-back half of the loop is one REST call per key:spend_available: false in that output means spend could not be totalled server-side; hold billing until it recovers rather than invoicing a zero.
(a) Bill from your pricing table
You define a markup over what the gateway shows you spent, and your Stripe/billing layer reads the spend numbers above and invoices.(b) Passthrough billing
For passthrough, your UI shows the same numbers you see in LangWatch + a per-customer markup or flat management fee.Handling over-limit customers
Whenon_breach: BLOCK, the gateway returns 402 budget_exceeded. Your customer sees:
- Show an upgrade CTA in the end-user’s UI.
- Fall back to a free-tier response (“you’ve hit your monthly cap; upgrade for unlimited”).
error.type.
Rotation & revocation
Customer resets their API key in your UI → you calllangwatch.rotate(vkId), get a new secret, send it to the customer. The old secret keeps authenticating for a 24 h grace window, so a client you have not reached yet does not start failing mid-rollout. The gateway’s cache TTL (~60 s) is only how long the new secret takes to be accepted everywhere, not when the old one expires.
Customer cancels their subscription → langwatch.revoke(vkId). The next request returns 403 virtual_key_revoked. If you want a grace period, schedule the revoke job for 24–48 h after cancellation instead.
Audit: who did what
Every write through your backend credential is audited with action, target, and before/after metadata. Scoped API keys attribute the write to the key’s owning user; legacy project keys carry no user, so their writes record the machine principalsvc_<your_project_id>. Filter the audit log on target virtual_key to get a per-customer provisioning history, under /settings/audit-log in the LangWatch UI.
If you need SIEM export: query ONLY the gateway-shape AuditLog rows with a read-only role scoped to that table, and ship the filtered result set, never a whole-database dump (which would carry unrelated, sensitive application data). For example, a daily job running COPY (SELECT id, "organizationId", "userId", action, "targetKind", "targetId", "createdAt" FROM "AuditLog" WHERE "organizationId" = '<your-org-id>' AND "targetKind" IN ('virtual_key', 'budget', 'model_provider', 'routing_policy', 'cache_rule') AND "createdAt" >= now() - interval '1 day') TO STDOUT WITH CSV into your SIEM’s ingestion path: an explicit column list pinned to your organization, leaving the before/after payloads out unless your SIEM genuinely needs them. There is no public REST audit-export endpoint in v1, see Audit log → Querying programmatically for the supported paths (UI CSV download, direct SQL).
Gotchas
- Never let the customer see your backend API token. It has
virtualKeys:create; they’d provision more VKs charged to you. - Rotate VKs when an end-user leaves your customer’s org. Otherwise the ex-user keeps spend access until the budget resets.
- Name keys after your tenant id (
customer-<id>) at creation time. The key’s name and id are your join keys for spend read-back and audit history;principal_user_idis only for real LangWatch user accounts, not your external customers. - Test the
402path in your app before go-live. Many apps have unhandled exceptions on budget breach and crash the user’s flow. - Budgets scoped to
virtual_keyare the right level for per-customer enforcement, and the inlinebudgetfield on create/update manages exactly that budget for you.
Rate limits at your gateway level
If you want to throttle a specific customer without moving them to a different plan:429 rate_limit_exceeded. Combine with a short-window budget (hour, minute) for finer control.
See also
- Management REST API: every endpoint used above.
- Virtual Keys: VK lifecycle semantics.
- Budgets: hierarchical scope logic.
- Security: how backend tokens are isolated from VK secrets.
- CI smoke-test cookbook: validate the full flow in CI.