put_api_settings_budget
const url = 'https://example.com/api/settings/budget';const options = { method: 'PUT', headers: { cookie: 'supacloud_session=<supacloud_session>', 'Content-Type': 'application/json' }, body: '{"api_mode_controls":"example","critical_threshold_percent":1,"hard_stop":true,"monthly_cap_usd":1,"provider_monthly_caps_usd":"example","threshold_alerts_percent":[1],"warning_threshold_percent":1}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PUT \ --url https://example.com/api/settings/budget \ --header 'Content-Type: application/json' \ --cookie supacloud_session=<supacloud_session> \ --data '{ "api_mode_controls": "example", "critical_threshold_percent": 1, "hard_stop": true, "monthly_cap_usd": 1, "provider_monthly_caps_usd": "example", "threshold_alerts_percent": [ 1 ], "warning_threshold_percent": 1 }'Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Examplegenerated
{ "api_mode_controls": "example", "critical_threshold_percent": 1, "hard_stop": true, "monthly_cap_usd": 1, "provider_monthly_caps_usd": "example", "threshold_alerts_percent": [ 1 ], "warning_threshold_percent": 1}Responses
Section titled “Responses”Updated workspace budget status
object
{ api_key, oauth, system } ⇒ bool toggles. Runtime stays
serde_json::Value; the spec types it as a Record<string, bool>.
object
The operator’s target window saturation in [0.0, 1.0] (e.g. 0.85) driving
the throttling_soon warning, from the autonomy policy. None → the surface
falls back to the Balanced default (GOTCHA-FILLTARGET).
#626 Nutzung — the same windows summed per (provider, window_type, scope) across
a provider’s connected accounts (the “2 KONTEN · summiert” popover header). Derived
from per_provider_windows; empty when there are no windows.
#626 Nutzung — one provider’s windows summed across its connected accounts, for the
“2 KONTEN · summiert” popover header. One summary per (provider, window_type, scope)
over the per-account [ProviderWindowStatus] list (the FE still lists the per-account
rows underneath). Computed by calculations::aggregate_windows_by_provider.
object
How many distinct accounts (credentials) contribute to this summary.
Percent of the summed window consumed, 0.0..=100.0; 0.0 when limit is None.
Sum of limit across the accounts — None when ANY account’s limit is unknown
(an unknown limit is not assumed zero; the summed gauge would mislead).
all (overall budget) or model:<id> (a per-model sub-budget) — windows are
summed only within the SAME scope (an all window is never folded into a
per-model one).
Sum of used across the accounts in this group.
'rolling_5h' | 'weekly' | 'monthly'.
ADR 0045 Stage 2a — per-credential subscription/API saturation windows
(one entry per (provider, window)), computed from the
provider_quota_state snapshots by calculations::window_status. Empty on an
API-key-only workspace with no quota snapshots (the $-bars above still apply).
ADR 0045 Stage 2a — one provider-quota window in the usage surface. Serialized by
GET /api/settings/budget and GET /workspaces/{id}/usage. The COMPUTATION (from
a [crate::services::provider_quota::QuotaState]) lives in
calculations::window_status; this is the wire shape (+ Default so callers
compile before that computation lands).
object
Human label for the credential’s account (OAuth account email), resolved in
load_budget_status. None when unresolved (e.g. an Anthropic OAuth token
whose scopes return no email — see the OAuth-email follow-up).
#626 Nutzung — 'primary' | 'overflow', DERIVED at read time (no column): per
provider, the credential with the MOST headroom in its all-scope window is the
primary (the one the quota-aware dispatcher prefers, mirroring
provider_quota::multi_key::resolve_credential_with_most_headroom); the rest are
overflow. Account-level — the same role is stamped on EVERY window of a
credential (incl. its per-model windows). None when the provider has a single
account (no overflow concept).
The credential this window belongs to. Lets the FE list per-account windows distinctly when one provider has several connected accounts (#555).
'oauth_subscription' | 'api_key' — drives the FE capability detection
(saturation gauges show only for subscription credentials).
Percent of the window consumed, 0.0..=100.0. 0.0 when the limit is unknown.
None = unknown limit (a new/Unsupported credential) ⇒ no gauge, no warning.
Whole minutes until resets_at; None if unknown.
#626 Nutzung — the subscription plan/tier badge (“Max 20x”, “ChatGPT Pro”, …)
read off the credential’s agent_oauth_tokens.plan_label (migration 263), resolved
in load_budget_status. None for an API key, a legacy row, or any provider whose
OAuth profile body exposed no plan at connect.
#626 D4.3 — the count of REDEEMABLE rate-limit-reset credits the provider
advertises for this credential window (Codex
rateLimitResetCredits.availableCount, migration 270). None = no reset-credit
surface (every non-Codex window, and a Codex window probed before the spine read
it). The FE renders it as a chip; the redeem/consume action is a follow-up.
When the window resets; None if unknown.
#626 H2 — the window’s scope: all (the credential’s overall budget) or
model:<id> (a per-model sub-budget, e.g. a Codex Spark or Claude Sonnet
window). ALWAYS present (the DB enforces NOT NULL DEFAULT 'all' and the
projection clones it verbatim), so it is a REQUIRED string in the contract —
no #[serde(default)] (this DTO is serialize-only; the attribute would only
drop it from the OpenAPI required set). The FE renders per-model windows
distinctly and sums per-account windows under one provider.
'real_limit_hit' | 'status_probe' | 'telemetry' | 'default' | 'task_boundary'
— snapshot provenance so the FE can distinguish a hard hit from a low-confidence
estimate.
True when fill_pct is within the throttling band of fill_target — the FE
surfaces an amber “approaching limit” state.
'rolling_5h' | 'weekly' | 'monthly'.
Per-provider in-flight reservation (USD). Runtime stays serde_json::Value;
the spec types it as a Record<string, number>.
object
Per-provider monthly cap (USD). Runtime stays serde_json::Value; the spec
types it as a Record<string, number>.
object
Per-provider month spend (USD). Runtime stays serde_json::Value; the spec
types it as a Record<string, number>.
object
Examplegenerated
{ "alerts": [ "example" ], "api_mode_controls": { "additionalProperty": true }, "critical_threshold_percent": 1, "effective_month_spend_usd": 1, "fill_target": 1, "hard_stop": true, "inflight_reserved_usd": 1, "month_spend_usd": 1, "monthly_cap_usd": 1, "per_provider_summary": [ { "account_count": 1, "fill_pct": 1, "limit": 1, "provider": "example", "scope": "example", "used": 1, "window_type": "example" } ], "per_provider_windows": [ { "account_email": "example", "account_role": "example", "credential_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "credential_type": "example", "fill_pct": 1, "limit": 1, "minutes_to_refresh": 1, "plan_label": "example", "provider": "example", "reset_credits": 1, "resets_at": "2026-04-15T12:00:00Z", "scope": "example", "source": "example", "throttling_soon": true, "used": 1, "window_start": "2026-04-15T12:00:00Z", "window_type": "example" } ], "provider_inflight_reserved_usd": { "additionalProperty": 1 }, "provider_monthly_caps_usd": { "additionalProperty": 1 }, "provider_spend_usd": { "additionalProperty": 1 }, "remaining_usd": 1, "status": "example", "threshold_alerts_percent": [ 1 ], "warning_threshold_percent": 1}Structured client error
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Authentication required
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Permission denied
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Structured server error
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}