Skip to content

Budgets

Janus supports daily spending limits and absolute per-key spending limits, measured in USD. Budgets are checked before routing: once a limit is reached, subsequent requests are rejected before reaching a provider.

  • Daily: spending during the current calendar day. Resets at midnight in the configured reporting timezone (server_reporting_timezone, UTC by default).
  • Absolute: all recorded spending for a specific Janus API key. Never resets, including across midnight, restarts, or budget edits. Spending from before the limit was configured also counts.

An API key can have either limit or both. A global daily budget can additionally limit spending across all keys. Reaching any applicable limit blocks requests.

Budgets are stored in SQLite, not YAML. Manage them with the CLI or the dashboard; changes take effect without a server restart.

Set an absolute budget

Give an existing key named dev-key a $25 total allowance:

janus budgets set --key "dev-key" --absolute 25

Or create a key with a lifetime cap, with or without a daily cap:

janus keys create --name "trial-key" --absolute-budget 25
janus keys create --name "limited-app" --daily-budget 5 --absolute-budget 25

For an existing key identified by its numeric ID:

janus keys update 3 --absolute-budget 25

If the key has already spent $8, setting an absolute limit of $25 leaves $17. Setting a limit below its recorded spend blocks new requests immediately; it does not grant a new allowance. To give that key $10 more after spending $25, increase the limit to $35.

Absolute budgets apply to SQLite-managed Janus client keys, not provider or inventory credentials. Static keys in YAML do not have individual database key identities and cannot receive per-key budgets. Global daily budgets still apply to their requests.

Thresholds and enforcement

Threshold Default What happens
Warning 80% Requests proceed. The dashboard shows a warning.
Reached 100% New requests are rejected with HTTP 429.

The warning threshold applies to both limits on the key. A daily rejection includes Retry-After, the number of seconds until the next reporting-day boundary. An absolute rejection has no Retry-After because waiting does not replenish it. Increase or remove the absolute limit to allow more requests.

Absolute rejection response

{
  "error": {
    "message": "Absolute budget exceeded. Spent $25.00 of $25.00 lifetime limit. This budget does not reset; increase or remove it to allow more requests.",
    "type": "budget_exceeded",
    "budget_period": "absolute",
    "total_spend": 25.0,
    "absolute_limit": 25.0,
    "resets_at": null
  }
}

Daily rejections retain type: "budget_exceeded", today_spend, and daily_limit, and explain the reporting timezone's midnight reset. If both limits are reached, the absolute rejection takes precedence because a daily reset cannot restore access.

Accounting limits

Budget amounts use Janus's recorded costs, based on configured model prices, not a live upstream billing balance. Unknown or intentionally unpriced models record $0 and therefore do not consume the budget. Configure prices for models you want to meter. Explicit pricing backfills can change historical costs and therefore change the measured lifetime total.

Like daily budgets, absolute budgets are admission checks, not prepaid balance reservations. An accepted request or concurrent in-flight requests can take the final recorded total above the cap. Requests already streaming are not interrupted. Usage recording and budget checks retain Janus's existing fail-safe behavior: database failures do not block requests.

Lifetime totals use the persistent usage history; clearing request logs does not clear spending. Removing and re-adding a budget does not reset its total. Deleting or altering usage records changes the accounting history, so retain that history when relying on lifetime budgets.

CLI management

List budgets

janus budgets list

The output distinguishes daily limits and today's spend from absolute limits and total spend. Budget status is ok, warning, or exceeded; when both limits exist, it reflects whichever is more restrictive.

Set or change limits

janus budgets set --key global --daily 10
janus budgets set --key "dev-key" --daily 5 --absolute 25 --warn 70
janus budgets set --key "dev-key" --absolute 35

Omitted limits stay unchanged. An omitted warning threshold keeps its existing value, or defaults to 80% for a new budget.

Option Description
--daily / -d Positive, finite daily limit in USD
--absolute Positive, finite lifetime limit in USD; requires a specific key
--key / -k Key name, or global for a daily gateway-wide limit
--warn / -w Warning threshold from 1 to 100 percent
--clear-daily Remove the daily limit without changing the absolute limit
--clear-absolute Remove the absolute limit without changing the daily limit

Provide at least one limit or clear option. You cannot set and clear the same limit in one command.

Remove limits

janus budgets set --key "dev-key" --clear-absolute
janus keys update 3 --clear-absolute-budget
janus keys update 3 --clear-daily-budget

Clearing both limits removes the budget. To delete the entire budget by its budget ID, use janus budgets delete 2; this removes both limits, not the API key or usage.

Dashboard management

  • On API keys, create or edit a key and set Daily budget (USD), Absolute budget (USD), or both. The edit form displays the current values. A blank field means no limit; clearing it removes that limit.
  • On Budgets, select Set budget. Both daily and absolute limit fields are visible immediately. Choose a specific API key under Scope to enable the absolute limit; Global gateway (daily only) does not support lifetime caps. If no keys exist, the dialog links to API-key creation. Existing limits load when selecting a scope or editing a row.
  • Spent today uses the reporting timezone's calendar day. Spent total shows lifetime spending when an absolute limit is configured. Blank total values for daily-only budgets are displayed as an em dash, not as zero lifetime spend.
  • At least one limit is required on the Budgets form. Use the row's delete button or clear both fields on the API-key edit form to remove the whole budget.

See also