BURNLENSDocsDashboard

Budgets and enforcement

Config keys read out of burnlens/config.py and burnlens/proxy/router.py on 2026-08-16.

Why this is different from an alert

An alert tells you that money is gone. Because the proxy sees a request before forwarding it, BurnLens can decline one that would breach a cap: the caller gets 429, the upstream request is never made, and the call never appears on a bill. That is the whole reason the proxy is a proxy and not a log shipper.

Where config lives

BurnLens looks for a YAML file in this order: the path in BURNLENS_CONFIG_PATH, then ./burnlens.yaml or ./burnlens.yml, then ~/.burnlens/config.yaml. Every example below goes in that file.

It is YAML, not TOML. A .toml file in the same place is not picked up, and the failure is quiet — your limits simply never apply.

Per-key daily caps

Register a key by label so caps can target it, then give the label a daily dollar limit. Raw keys are never displayed back to you.

burnlens key register --label prod-openai --provider openai
burnlens key list
burnlens keys              # today's spend per label against its cap
burnlens keys --json       # same, machine-readable

The caps themselves nest under alerts:, which is not guessable from the CLI:

alerts:
  api_key_budgets:
    reset_timezone: Asia/Kolkata   # IANA name; an invalid value falls back to UTC
    prod-openai:
      daily_usd: 50.0
    default:                       # registered labels with no override of their own
      daily_usd: 5.0

At 100% of recorded spend the proxy returns 429 before forwarding. This is a recorded-spend guardrail, not an absolute concurrent ceiling: requests already in flight and simultaneous uncached checks can overshoot. The 50% and 80% thresholds fire alerts instead of blocking. Run burnlens controls to inspect the active scope and guarantees.

Team and customer budgets

These are keyed on the tag values described in tagging — untagged traffic cannot be budgeted, so tag first.

alerts:
  budget:                    # your own overall spend
    daily_usd: 100.0
    monthly_usd: 2000.0
  budgets:                   # per-team, from X-BurnLens-Tag-Team
    global: 5000.0
    teams:
      platform: 2000.0
      growth: 500.0
  customer_budgets:          # per-customer, from X-BurnLens-Tag-Customer
    default: 50.0
    customers:
      acme-corp: 500.0
burnlens budgets       # per-team status for the current month
burnlens customers     # per-customer spend and budget status

Virtual keys

A virtual key lets you hand a team a token instead of the real provider key. The real key stays in an environment variable on the proxy host; the virtual key carries a monthly budget and an optional model allowlist, and can be revoked without rotating anything upstream.

burnlens vkey issue --label growth-team --team growth \
  --provider openai --upstream-env OPENAI_API_KEY \
  --budget 500 --allow gpt-5.6-terra,gpt-5.6-sol

burnlens vkey list
burnlens vkey revoke --label growth-team

The raw token is printed once, at issue time, and never stored — so it can never be shown again. Store it when you see it.

Unpriced models are blocked by default

A model with no pricing entry costs BurnLens $0. Its spend therefore never advances a budget, and a cap covering it would enforce nothing at all. Rather than let a cap silently become decorative, such a request is rejected with 403.

block_unpriced_models: true   # default

This only applies where a budget actually covers the request. Uncapped traffic on a brand-new model is unaffected. Set it to false if you would rather have availability than enforcement — for instance when a provider has shipped a model before BurnLens has shipped its price — and its spend then counts as $0. Check burnlens pricing to see what is priced.

Budget-aware model downgrade

Instead of hard-blocking, BurnLens can route a request to a cheaper model as a budget runs low. This policy can change the model sent upstream. It is off by default — observation does not rewrite model. It only ever activates once a budget exists and you set budget_downgrade: true.

routing:
  budget_downgrade: false       # default — set true to opt in
  downgrade_threshold_pct: 20   # under 20% of the budget remaining
  downgrade_threshold_usd: 5.0  # ...or under $5 remaining
  log_downgrades: true          # default

The percentage check runs first, so when both would trigger the reason is recorded as budget_pct. Every downgrade is logged and burnlens routing shows the activity. Leave budget_downgrade false (or omit it) to always receive the model you asked for and take the 429 instead.

Runtime-changing policies

Observation, cost calculation, and attribution run by default. Anything that changes what the provider receives, or skips the call, is an explicit policy.

PolicyDefaultTriggerActionAuditRollback
Hard cap (per API key)Off until a cap is setKey daily spend reaches 100%HTTP 429 before upstreamRequest log status 429Raise or remove the key cap
Budget-aware model downgraderouting.budget_downgrade: falseRemaining budget below 20% or $5Rewrite model upstreamrequested_model, model (effective), routed_model, downgrade_reasonSet the flag false or omit it
Semantic cachecache.enabled: falseExact or similar prompt, policy onServe locally; no upstream callCache hit / cache_saved_usdSet cache.enabled: false

Exact enforcement semantics

Behaviour under concurrency, streaming responses, retries and unpriced models — with the implementing function cited for every claim — is documented in BUDGET_ENFORCEMENT.md. Read it before relying on a cap as a financial control rather than a guardrail.

All documentation

  • Overview & install — What BurnLens is, how to install it, and which of the two entry points you want.
  • Scanning coding agents — Import Claude Code, Cursor, Codex and Gemini CLI cost history from local logs.
  • Proxy & tagging — Route production API traffic through the local proxy and attribute it with tags.
  • Budgets & enforcement — Daily key caps, control scope, concurrency guarantees, virtual keys, downgrade routing.
  • Cost evidence — Cost Confidence, Outcome Coverage and Verified Savings — how much of a number BurnLens can prove.
  • Known limitations — Where each figure stops being authoritative, stated plainly.
  • CLI reference — Every burnlens command, and where the config file and database live.

Something here wrong or missing? Open an issue or email support@burnlens.app.