Skip to main content

Documentation Index

Fetch the complete documentation index at: https://langwatch.ai/docs/llms.txt

Use this file to discover all available pages before exploring further.

A virtual key (VK) is a LangWatch-issued credential that a downstream client (SDK, coding CLI, production app) presents to the gateway in place of a provider-native API key. The gateway resolves the VK to an owning scope, a set of provider credentials, a fallback chain, a cache policy, guardrails, blocked patterns, and budgets — everything the VK is allowed to do and how it is observed. VKs replace raw provider keys in your applications. The provider keys themselves stay inside LangWatch (configured under Settings → Model Providers, the same surface you already use for evaluators and playground) and are never shared with downstream clients.

Quickstart — first request in 5 min

Create a VK, call /v1/chat/completions, read correlation headers.

Use your VK from Python / TypeScript

OpenAI / Anthropic SDK drop-in — just swap base_url and api_key.

Plug your VK into Claude Code / Codex / Cursor

Route coding-assistant traffic through the gateway for budget + audit.

Manage VKs from the terminal

langwatch virtual-keys create | list | rotate | revoke — scriptable.

Format

lw_vk_{live|test}_<26-char-ULID> — 40 characters total.
  • lw_vk_ — fixed prefix, grep-friendly, scans well in DLP / GitGuardian.
  • live or test — environment prefix. Prevents accidentally using a test key against production or vice versa.
  • 26-char Crockford-base32 ULID — time-prefixed, monotonic, renders sensibly in the dashboard and in your logs.
The secret is shown exactly once at creation. After you dismiss the creation dialog it can never be retrieved again — only the first 12 characters (lw_vk_live_01HZX9) are visible in the list. Server-side, the secret is stored as hex(hmac_sha256(server_pepper, secret)). Peppered HMAC-SHA256 is the right primitive for API keys (as opposed to passwords) — the VK body already carries 130 bits of entropy as a ULID, so argon2id-style stretching would just add 50–100 ms of pointless latency on every cold resolve-key call. A short prefix is stored alongside for grep/lookup.

Creating a VK

Under AI Gateway → Virtual Keys click New virtual key and fill:
FieldMeaning
NameHuman label. Used in the UI and in langwatch.vk.name trace attribute.
Environmentlive (default) or test. Reflected in the key prefix.
Primary provider credentialsThe credentials the gateway uses first. Dropdown of Model Provider entries on this project.
Fallback chainOrdered list of additional provider credentials. Any failures on the primary (5xx / timeout / 429 / network) attempt the next in order.
Models allowedOptional allowlist. Blank = “any model the provider credentials support.”
Model aliasesMap of client-friendly names → provider/model. E.g. gpt-4o: azure/my-deployment.
Cache policyrespect (default), force, or disable.
GuardrailsAttach existing LangWatch evaluators as pre / post / stream_chunk hooks — the drawer has a dedicated picker section listing every project evaluator with executionMode = AS_GUARDRAIL. Fail-open toggles on pre and post directions surface the concrete 403 / 50 ms / terminal-SSE enforcement shape so operators know what the toggle actually does. See Guardrails → Attaching guardrails to a VK.
Blocked patternsRegex allow/deny for tool names, MCP servers, URLs.
Initial budgetOptionally attach a budget on creation. Budgets can always be added later.
Click Create. The full secret is revealed inline with a Copy button and a I’ve saved it, close confirmation that must be checked before dismissing. After dismiss, the secret is gone for good.

VK detail page

Clicking a row in the list opens the detail page (/gateway/virtual-keys/<vk_id>). Four sections, top-to-bottom:
  1. Header — name + action bar: Audit history (deep-links into /settings/audit-log?targetKind=virtual_key&targetId=<vk_id> with a pre-filled filter chip showing only this VK’s events alongside any related platform actions), Edit, Rotate, Revoke. The Audit history deep-link is the fastest way to reconstruct “who changed this VK, when” during an incident.
  2. Identity / Activity — id, prefix, environment, status, description, and humanised Last used + Created (hover for exact timestamp). Revision number shown when non-zero — increments on every gateway.virtual_key.updated audit row.
  3. Provider fallback chain — ordered rows, each showing provider icon + readable name + slot badge (primary / fallback-1 / fallback-2 / …) + credential id. Clarifies at-a-glance which provider is in the driver’s seat and what falls back when it errors.
  4. Configuration summary — compact read-only view (no drawer needed) of the runtime config that’s actually in effect:
    • Tags — colored subtle badges, the same strings shown on the list row.
    • Cache mode — badge (respect / force / disable) + TTL on force.
    • Rate limitsrpm + rpd outline badges (or em-dash if unset).
    • Model aliases — expanded as alias → target pairs, up to 5 visible with “+N more” overflow.
    • Blocked patterns — grouped by dimension (tools / mcp / urls / models) with red-tinted regex chips; click-through opens the edit drawer at that section.
    • Guardrails — count + direction breakdown (N pre / M post / K stream_chunk), each clickable to the guardrail config.
  5. Usage (last 30 days) — stat tiles (Total spend / Requests / Avg $/request), a 30-day filled area sparkline, Spend-by-model row, and the top 10 recent debits table (When relative / Model / Tokens in→out / Amount smart-decimals / Latency ms). Guarded on virtualKeys:view + gatewayUsage:view.
Everything on this page is read-only except the four header actions — edits happen in the drawer (Edit) or dedicated flows (Rotate / Revoke).

Rotation

Rotate a VK when you believe the secret may have leaked or as part of routine hygiene.
  1. Open the VK in the list.
  2. Click Rotate secret.
  3. LangWatch mints a new secret and displays it exactly once.
  4. The old secret remains valid for a 24-hour grace window to let in-flight deploys update.
  5. After the grace window ends, only the new secret works.
Rotation keeps the same vk_id, same ownership, same configuration — only the secret changes. Observability traces remain continuous across rotation.

Revocation

Revocation immediately invalidates the secret. There is no grace period on revoke. Gateway caches are invalidated within 60 seconds via the /internal/gateway/changes long-poll. If you need instant invalidation everywhere (e.g. incident response), restart the gateway pods — the next request that hits them will pull fresh state before serving. Revoked VKs remain in the database (soft-delete) for audit. Their traces still appear in analytics.

Scoping

A VK belongs to exactly one project. The project’s team and organisation are implicit owners. Traffic attribution on every trace:
  • langwatch.virtual_key_id
  • langwatch.project_id
  • langwatch.team_id
  • langwatch.organization_id
  • langwatch.principal_id — the user or service account that owns the VK (for principal-scoped budgets)

Personal access vs shared

Two flavours:
  • Personal access VK — bound to one user principal. Best for “give the engineer a key their local tools can use.” Inherits budgets scoped to that user.
  • Shared VK — bound to a service-account principal. Best for applications. Can be rotated independently of user offboarding.
Both use the same lw_vk_live_… format; the difference is the principal the VK resolves to and which budgets apply.

Permissions

Acting on VKs requires the following permissions (2-segment resource:action):
ActionPermission
View listvirtualKeys:view
CreatevirtualKeys:create
Update configvirtualKeys:update
RotatevirtualKeys:rotate
Delete / revokevirtualKeys:delete
All of the abovevirtualKeys:manage
See RBAC for default role mappings.

How the gateway resolves your VK

The first time the gateway sees a presented VK:
  1. Calls /internal/gateway/resolve-key on the LangWatch control-plane → receives a signed JWT (15-minute TTL) with identity claims (vk_id, project_id, principal_id, etc.) plus a revision number.
  2. Calls /internal/gateway/config/:vk_id (with If-None-Match: <revision> on subsequent fetches) → receives the fat config (providers, fallback, guardrails, budgets).
  3. Caches both in-memory (L1 LRU) and optionally in Redis (L2, shared across gateway pods).
  4. Subscribes to /internal/gateway/changes?since=<revision> long-poll — on any mutation to any VK, the gateway invalidates and re-fetches.
Subsequent requests with the same VK are served entirely from cache. JWT verification is local (HS256 shared secret); no control-plane round-trip on the hot path. This means:
  • First request on a cold cache: 2-4 ms of control-plane overhead.
  • Warm request after first: tens of microseconds of overhead.
  • Control-plane offline: gateway continues serving from warm cache until JWT TTL expires (15 min default); with bootstrap mode on, it can serve indefinitely.
See Self-Hosting → Config for tuning the cache.