langwatch CLI and LangWatch dashboard use, exposed for scripts, CI pipelines, SDKs, and terraform providers. It runs on the LangWatch control plane (https://app.langwatch.ai), separately from the data-plane gateway (https://gateway.langwatch.ai).
Authentication uses existing LangWatch API tokens (Authorization: Bearer lwp_... or X-Auth-Token: lwp_...). No new token format.
The CLI (
langwatch virtual-keys ...) is built on this API. If you’re scripting from Node or Python, consider using the CLI rather than calling the REST directly, it handles pagination, JSON formatting, and error messages for you.Base
Virtual keys
List
purpose: "langy" marks a product-managed key (auto-provisioned by LangWatch). Those rows appear in listings but refuse every mutation; filter on purpose when scripting bulk operations.
Create
name is required):
scopesdefaults to the calling project. Team- and org-scoped keys need a scoped API key holdingvirtualKeys:manageat each requested scope; legacy project keys can only mint keys for their own project.- An org- or team-scoped key also needs a place for its traces and spend to land: pass
trace_project_id(requiresvirtualKeys:manageon that project; it is a destination, not a scope, and grants no access to the key), or the organization’s governance project is used, and creation refuses withtrace_project_requiredwhen neither exists. budgetcreates a budget atomically with the key and manages exactly that row on later updates: the key can never exist without the cap you asked for. Windows:DAY,WEEK,MONTH.routing_modeis one ofNONE(default: no silent failover),FALLBACK_ALL, orPOLICY(requiresrouting_policy_id).
201:
Get
{ "virtual_key": {...} }. No secret.
Spend
gatewayUsage:view. Both window params are optional; the default window is the current UTC calendar month. Reads the same cost path (trace_summaries) the dashboard reads, so this number and the UI agree by construction.
Response:
412 with error.code = "spend_source_unavailable" rather than a $0.00 that cannot be told apart from a zero-spend key.
Update
scopes replaces the whole visibility set and requires virtualKeys:manage at every NEW scope. budget: null archives the key’s own cap (spend history is retained); omitting budget leaves it alone.
Rotate
200:
Revoke
200 with the same status. Revocation also archives the key’s own budgets.
Budgets
List
ORGANIZATION, TEAM, PROJECT, VIRTUAL_KEY, PRINCIPAL, GROUP), with live spent_usd from the spend ledger. scope_type is an optional comma-separated filter.
Response:
spend_available: falsemeans spend could not be totalled server-side; do not readspent_usdas real spend in that case.GROUProws are per-member allowances:limit_usdis what EACH member may spend,spent_usdis the group’s summed spend, andmember_countsays how many members the allowance currently covers.provider_keynames the ModelProvider the budget is pinned to;nullcounts every provider.
Create
GROUP budgets track spend per member, which requires the ClickHouse spend ledger; deployments without it answer 400 with error.code = "group_budget_requires_clickhouse".
Update
name, description, limit_usd, on_breach, timezone. Scope and window are immutable after create.
Archive
archived_at set.
Provider bindings
The/providers routes are gone (410). Gateway provider bindings were folded into the platform-wide ModelProvider in iteration 110: configure credentials, rate limits, and fallback priority via /api/gateway-platform/v1/model-providers or the Advanced (Gateway) tab in the dashboard. Budgets reference providers by ModelProvider id (provider_key).
Cache rules
Organization-scoped overrides that modulate cache behaviour for requests routed through the gateway. Evaluated first-match-wins by priority DESC; a matched rule wins over the per-VK default but loses to a per-requestX-LangWatch-Cache header. Full contract in Cache control.
List
gatewayCacheRules:view. Returns rules sorted priority DESC, excluding archived.
mode_enum is echoed in upper case alongside the lower-case action.mode so Prometheus, dashboards can filter by it without parsing the JSON action.
Get
gatewayCacheRules:view. Returns 404 for archived rules, use the audit log to inspect removed rules.
Create
gatewayCacheRules:create. At least one matcher is required (rules that match every request must be declared explicitly, unsupported in v1). Matchers across non-null fields are ANDed.
Action fields:
Response
201: { "cache_rule": { ...full row } }.
Update
gatewayCacheRules:update. Partial update; matchers and action replace the stored value when provided (not merged field-by-field). Omitting them leaves the stored value untouched. Name, description, priority, enabled update independently.
Archive
gatewayCacheRules:delete. Soft archive: sets archivedAt. The rule stops matching new requests. Returns the archived row (200, not 204) so scripts can confirm the archivedAt timestamp.
Errors
All responses follow the OpenAI-compatible envelope:error.code carries the machine code your integration can branch on (validation_error, trace_project_required, routing_policy_required, scope_org_mismatch, group_budget_requires_clickhouse, spend_source_unavailable, …). See API: Errors for the full type enum.
Common management-side types:
Audit
Every write emits a row in the platform-wideAuditLog (gateway shape, targetKind, targetId, before, after). Visible under /settings/audit-log with the Source = “Gateway” badge; filter by Target (virtual_key, budget, cache_rule) to scope. Writes via scoped API keys are attributed to the key’s owning user; legacy project keys carry no user, so their writes record the machine principal svc_<projectId>. See Audit log for the full schema, REST export path, and migration note from the v3.0 gateway-only table.
Rate limits
Management endpoints are rate-limited to 100 req/min/token. For bulk operations, use the--format json CLI with xargs -P4 (the CLI sleeps 250 ms between retries on 429).
Shared service layer
Both the REST API and the tRPC routers (virtualKeys.*, gatewayBudgets.*, gatewayUsage.*) call the same service classes and pre-flight asserts on the server: VirtualKeyService, GatewayBudgetService, GatewayUsageService, and the scope-authorization helpers in virtualKey.authz. The only difference between REST and tRPC is the DTO shape (snake_case vs camelCase) and how the caller is identified (API credential vs browser session). Behaviour is identical, and the integration suite in langwatch/src/app/api/gateway-platform/__tests__/ pins the refusals (trace_project_required, per-scope permission_denied, group_budget_requires_clickhouse, …) so the two surfaces cannot drift apart again.
OpenAPI
All REST routes are annotated withhono-openapi’s describeRoute schemas, which generate into the repository-wide OpenAPI 3.1 document (docs/api-reference/openapiLangWatch.json) rendered by the API-reference docs. The CLI’s VirtualKeysApiService and GatewayBudgetsApiService DTOs are hand-authored against the same schemas; a future improvement is to regenerate them from the OpenAPI output so drift fails at build time.
See also
- langwatch CLI: higher-level access.
- RBAC: which scopes your token needs.
- Security: how your API tokens and resulting writes are protected.