alert threshold the platform records an event and posts to your webhook. When it crosses a block threshold the gateway rejects further billable requests with 403 budget_exceeded until the period resets.
Budgets count spend from every billable service on the platform, priced at the rate in effect when each request ran. Enforcement is best-effort and fail-open: when the budgeting service is unreachable, the gateway lets the request through. Size limits with margin.
This guide caps one end user, sets a default cap for every end user, caps the whole organization, and shows what a blocked request returns.
The mka1 CLI has no budgets commands, so this guide has no CLI tab.
Before you start
Scopes
Every budget targets one scope. Theid you pass is the ID of the thing being capped.
A default is a rule, not a counter. It caps each member, team, or end user against their own spend, so alerts and blocks fire per target, and it has no spend gauge of its own. An explicit budget for one target replaces the default of the same owner and period for that target, whether it raises or tightens the cap. Delete the explicit budget and the default applies again.
Every budget also has an
owner. org is a self-budget the organization sets on itself. cluster is an operator ceiling that only a cluster admin can set or change; see For cluster admins. One budget exists per scope and owner, so a scope can carry both, and a request has to pass every budget that applies to it. The most restrictive one wins.
What a budget holds
Each response also carries
id, scope, scope_id, scope_org_id, and a live spend gauge: { "window", "cost_spent", "limit", "pct", "status" }, where status is ok or blocked. For user, team, and external_user scopes, scope_id is <org-id>:<id>.
Step 1 - Read the cluster currency
A cluster admin sets one currency for the whole cluster. Read it from the effective price card, which any bearer can read and which also lists the rates your spend is priced at.currency is null until the operator sets one.
budgets.getCurrency() reads the budgeting service’s copy of this code, but it is cluster-admin only; see For cluster admins.
Step 2 - Cap an end user
This example caps one end user at 5 per day, warns at 80%, and blocks at 100%. Theid is the value you send in X-On-Behalf-Of on that user’s requests. Setting a budget is an upsert: calling it again for the same id and owner replaces the budget and re-evaluates it against live spend.
setUser, setTeam, and setApiKey({ apiKeyId, requestBody }); the platform overview shows a key budget end to end. The organization’s own budget takes no id at all; see Step 6.
Step 3 - Read a budget and its live spend
A scope can carry a self-budget and an operator ceiling, so reads return a list.spend is the live gauge for the current window. status flips to blocked once spend crosses a block threshold and back to ok when the window resets.
Step 4 - Review threshold events
Each time spend crosses a threshold, the platform records an event with the spend and limit at that moment. Events for a default cap name the member, team, or end user they fired for intarget_id.
id, budget_id, type (threshold_alert or blocked), pct (null when the event was not tied to one threshold), period_key, target_id, spend_snapshot, limit_snapshot, and created_at.
Step 5 - Set a default cap for every end user
A default cap applies to each end user individually, not to all of them together. Set it once and every end user without an explicit budget of the same owner and period is capped against their own spend. The same operations exist for members (setUserDefault) and teams (setTeamDefault).
deleteExternalUserDefault({ owner: 'org' }); only explicit budgets remain.
Step 6 - Cap the whole organization
An organization budget counts everything the organization spends, across every key, member, team, and end user. It takes noid: the target is the caller’s own organization. Cluster admins can also cap another organization, or put a ceiling on it; see For cluster admins.
403, and Compute terminates a running service or job with no grace period.
Step 7 - Delete a budget
Deleting takes the sameid as setting, plus the owner of the budget to remove, because a scope can carry one of each. Enforcement and alerts stop at once. For a member, team, or end user, the organization’s default cap of the same owner and period applies to them again.
List every budget
One call returns everything you can see. A cluster admin sees every budget on the cluster. An organization admin sees the organization’s budgets, its default caps, and the budgets on its API keys. Default caps come back without aspend gauge.
How enforcement works
The gateway asks the budgeting service for a verdict before it dispatches any billable request, and sends the full identity of the caller: organization, API key, member, team, and theX-On-Behalf-Of end user. The budgeting service checks every budget that applies to that identity, from the organization’s budget down to the end user’s own cap. The gateway does not gate control-plane routes that cost nothing.
On /responses, the check runs after the model resolves, so an unknown or inactive model still returns 404 before a budget block returns 403.
What a blocked request returns
scope tells you which budget blocked the request: org, apikey, user, team, external_user, or one of the *_default rules. When a *_default rule blocks, the response never names the member, team, or end user it landed on; read that rule’s events endpoint for it. Some endpoints add "type": "permission_error" to the same envelope, so match on code, not type.
The MKA1 SDK raises APIError (statusCode === 403) in TypeScript, APIException in C#, and SDKDefaultError (status_code == 403) in Python. Unlike a 429, retrying does not help: the request stays blocked until the period resets or an admin raises or deletes the budget.
APIException and read its Body the same way; rate limiting shows that shape.
Best-effort, fail-open
The gateway gives the budget check 1.5 seconds. If the budgeting service is down, slow, or returns something the gateway does not recognize, the request goes through and the gateway logsbudget_enforcement_fail_open.
Two more things let a client at its limit overshoot by a few requests. The gateway caches each identity’s verdict for 3 seconds, and it reports spend to the budgeting service in batches, so the counter lags the requests it counts by a fraction of a second, longer if a push fails and is retried. Leave headroom below the amount you can actually spend.
How spend is attributed
The platform prices every billable unit at the rate in effect when it ran, and a later price change does not reprice it. Each unit reaches the budgeting service tagged with the organization, API key, member, team, end user, model, and task type, which is whatgroup_by below can split on. Spend windows reset on UTC calendar boundaries; the gauge names them as 2026-07-07, 2026-W28, or 2026-07 for daily, weekly, and monthly budgets.
A unit with no cost counts against nothing: a model with no price rates to zero, and a unit the gateway could not rate at all, as during a pricing outage, gets a null cost. If a budget’s gauge stays at 0 while requests flow, check the model’s price under Admin → Pricing before you check the budget.
To see where the money went, usage.costs sums cost over a time range across every billable service. Its group_by is a comma-separated string of any of service, task_type, model, api_key_id, team_id, user_id, external_user_id, and org_id, in curl and in every SDK:
llm.usage.costs, covers LLM spend only and types groupBy as an enum of model, api_key_id, team_id, external_user_id, and org_id.
In the console
Admin → Budgets manages the same budgets with three tabs:- Organization (or Organizations in cluster scope): the organization’s self-budget and operator ceiling, each with its live gauge.
- Members: explicit member budgets plus the organization’s per-member default cap. The default cap row has no gauge; its History action lists the members it has fired for.
- API keys: cluster scope only; see For cluster admins.
ok or blocked. The History action on a row expands its thresholds and the period’s alert and block events. Team and end-user budgets, and their defaults, are API-only.
Reference
Python uses the same names in
snake_case with flat keyword arguments, for example sdk.budgets.set_user(id=..., period=..., limit=..., thresholds=[...], owner="org"). C# uses PascalCase with an Async suffix and a body parameter, for example sdk.Budgets.SetUserAsync(id: ..., body: new SetUserBudgetRequestBody { ... }). Request types live in MeetKai.MKA1.Types.Requests. The optional orgId on every organization-scoped operation is for cluster admins; see the next section.
For cluster admins
Everything in this section needs a cluster admin bearer. Organization admins get
403 here.- Operator ceilings. Pass
owner: 'cluster'to any set operation to put a ceiling on that scope. Organization admins can read it but not change it, and it applies alongside their ownorgbudget; the most restrictive wins. Delete it with the sameowner: 'cluster'. - Other organizations. Every organization-scoped operation takes an optional
orgId(org_idin Python and curl) that targets another organization instead of your own.list()returns every budget on the cluster. - API-key budgets in the console. The API keys tab on Admin → Budgets appears only in cluster scope, which needs the cluster organization to be the active one; a cluster-admin role held from an organization session is not enough. Budgets made there always carry
owner: "cluster". - Display currency.
budgets.getCurrency()andbudgets.setCurrency()read and set the ISO 4217 code the budgeting service shows on budgets and cost reports. It is a display copy. Spend is rated in the price book’s currency, whichsetClusterCurrencysets (see Manage models); the currency control under Admin → Pricing writes both. Over the API, set both, once, before the first budget, because neither converts any amount. If the console shows the two apart after a first save, save again.
Troubleshooting
API reference
For the full request and response schemas, open the Budgets, Settings, and Usage groups in the API Reference.See also
- Rate limiting - request-count limits, which return
429instead of403. - Authentication - API keys, scopes, and the
X-On-Behalf-Ofpattern that identifies end users. - Platform overview: Budgets - the console walkthrough and an API-key budget example.