Usage Limits & Budget Rules
Set spending, token, and request budgets for your apps, teams, and gateway to control how much they can use.
Budget Hierarchy
Limits at every level apply together. The gateway checks its own limits, parent team limits, and app limits. An exhausted Block limit rejects the request unless the normal provider path uses a configured quota fallback. Warn limits allow the request and report the warning. Budgets cover these levels:
- Gateway - Limits across the Zuplo project (for example, $1,000/day), covering all teams, sub-teams, and apps combined
- Teams - Limits covering the team's own usage and every descendant sub-team and app (for example, $500/day for the Engineering team)
- Apps - Per-app limits for granular control (for example, $10/day for a hackathon app)
For example, a team has a $50 monthly shared Block budget. App A spends $40
and App B spends $10. Once that usage is reflected in the budget check, both
apps have reached the team's budget. Without a quota fallback, requests through
both apps receive 429 Too Many Requests. An app outside this team doesn't
share its $50 budget, but still has its own app, team, and gateway limits.
App budgets can add up to more than their team's budget. The team's budget caps the combined usage; increasing an app's budget doesn't increase its team's cap. The same rule applies to nested teams and the gateway root.
Where limits are configured
| Level | Budgets | Where to configure |
|---|---|---|
| Gateway | Shared | Settings → Usage Limits |
| Team | Shared | The team's Usage & Limits tab |
| App | Shared and per-metadata | Budgets and Costs in the app's policy chain |
Use Budgets and Costs to set an app's own budget.
New apps inherit their initial budget settings from their team policy template. To limit the team's combined usage, set a budget on Usage & Limits.
How a budget rule works
Each budget rule defines who shares the budget and how much they can use.
Scope decides who shares the budget:
| Scope | What it budgets |
|---|---|
| Shared | One budget for the app, team, or gateway |
| By metadata | A separate budget for every distinct value of an expression |
A By metadata rule gives each distinct expression value its own allowance.
With the expression request.headers.get("x-user") and a $5 daily cap, every
distinct x-user value gets its own $5 per day—one user exhausting their budget
doesn't affect anyone else. An app can combine a shared budget with several
per-metadata budgets.
Limit rows set the caps. Each row is a meter, a period, an amount, and an action:
| Field | Values |
|---|---|
| Meter | Cost (dollars), Tokens (input plus output), Requests |
| Period | Hourly, Daily, Weekly, Monthly |
| Limit | An absolute amount in the meter's own unit |
| Action | Block rejects the request; Warn notifies without blocking |
Add as many rows as you need to cap several meters and periods at once. A Warn row and a Block row on the same meter and period give you warn-then-block—warn at $80, block at $100. The warn amount has to be the lower of the two.
The Overview tab charts daily and monthly usage only. Hourly and weekly rows are enforced, but no meter on that tab tracks them.
Budget rule periods follow the UTC calendar
Hourly periods reset at the top of each hour, daily at 00:00 UTC, weekly on Monday at 00:00 UTC, and monthly on the first of the month. A rule added mid-period gets the full allowance for the rest of that period—the limit isn't prorated—and resets at the next boundary. Changing a limit mid-period doesn't reset the period's usage. Custom anchors aren't configurable.
Setting an app's limits
-
Open the Apps & Teams tab and select the app.
-
On the Policies tab, configure the Budgets and Costs policy (add it from Add Policy if the chain doesn't have it).
-
Select Add rule, choose the scope, and use Add limit to add rows for the meters and periods you want to cap. For a By metadata rule, enter the expression that identifies each caller.
-
Select Apply, then Save changes on the policy chain. See Propagation and accounting delays for when the change takes effect.
The app editor shows team and gateway budgets under Inherited. To change one, open the team or gateway where you set it.
Budget expressions
A By metadata rule identifies each caller with an expression evaluated per request. The editor validates it as you type. Available values include:
request.headers.get("x-user")and other request headersrequest.user.subandrequest.user.data.<key>from the authenticated API keyrequest.url,request.method,request.query,request.searchParams, andrequest.paramscontext.contextId,context.requestId,context.route, andcontext.custom
The editor labels each expression by where its value comes from, because that
decides how much the budget can be trusted. A client-supplied value—a header
or query parameter—is attribution, not enforcement: a caller who changes it gets
a fresh budget. Budget on request.user.*, labeled verified, when the
segment itself has to hold, and keep a shared-budget rule alongside it as the
hard cap.
Changing an expression starts a new budget. The old rule's usage stays with the
old expression, so every value's accounting restarts from zero. Expressions are
also case-sensitive: get("X-User") and get("x-user") read the same header
but budget separately.
To configure budgets in JSON, use the budgetRules option in Budgets and
Costs. For the available options, see the
Budgets and Costs policy reference.
This rule set budgets each user, each organization, and the app as a whole:
Code
Every distinct x-user value gets its own 20,000 tokens per hour, resetting at
the top of the hour. Every distinct x-organization value gets its own $50 per
day, resetting at 00:00 UTC. The app rule caps the whole app at $2,500 per
month, warning at $2,000, resetting on the first of the month.
Checking what a rule resolved to
A By metadata rule whose expression resolves to nothing budgets nothing, and the request still succeeds. A rule that silently does nothing therefore looks exactly like a rule that's working. Your gateway's request logs say which it is.
Every request that runs at least one By metadata rule logs
AI Gateway budget dimensions resolved, listing the rules that resolved and the
rules that didn't. Each rule that didn't carries a reason:
| Reason | What to change |
|---|---|
no-such-property | The expression is valid but found no value. The message names the property that broke the chain—check that the header or claim is really on the request. |
invalid-syntax | The expression is outside the grammar. The message gives the position of the problem. |
per-request-identifier | The value is unique to every request, so no two requests share a budget and no threshold is ever reached. Key on something that repeats, like a user or an organization. |
internal-field | The value comes from a field the proxy populates, such as client certificate material. |
value-not-scalar / value-not-safe-integer | The value isn't a string or a whole number. |
value-too-long | The value is longer than 256 bytes. |
value-has-control-characters | The value contains control characters. |
Resolved entries record the length of each value, not the value itself. A rule
whose expression names a credential—anything whose text contains token,
secret, authorization, password, cookie, credential, bearer, or
api_key in any spelling—never logs its value at all. Budgeting per API key is
a reasonable thing to do, and the key stays out of the log.
A rule that can never work, because its expression is unusable or the rule fails validation, also logs a warning. Those warnings arrive once per configuration rather than once per request, so a broken rule doesn't flood the log.
Verdicts name their rule too. A block or warning from a By metadata rule
carries the expression and its ruleId; one from an app-wide budget carries
neither. That's how you tell which rule refused a request.
Setting team and gateway limits
A team budget covers the combined usage of its apps and sub-teams. A gateway budget covers all apps in the project.
To add a shared team rule, select the team or sub-team in Apps & Teams, then open Usage & Limits. To add a shared gateway rule, open Settings → Usage Limits. Both editors use the same meter, period, amount, and action rows as the app editor.
The editor shows budgets from parent teams and the gateway under Inherited. To change an inherited budget, edit it on the team or gateway where you created it.
When a limit is exceeded
For a request continuing to a provider, an exhausted Block limit uses the app's configured quota fallback model instead of blocking. See Fallback Models, where the fallback model is selected. This applies to gateway and team limits as well as the app's own. The fallback's usage still counts toward the limits.
Without a quota fallback on that path, the request is rejected with
429 Too Many Requests and a budget object naming what ran out:
Code
The scope tells the caller which budget they hit. It is application when the
gateway, a team, or the app exhausts a shared budget. It is dimension when a
value exhausts an expression budget. Quote the ruleId when raising a support
request.
Successful cache responses
Cached responses are subject to budget limits too. If a Block budget is
exhausted, a cache hit returns 429 Too Many Requests instead of the cached
answer. Quota fallback doesn't apply to cache hits. Warn limits allow the
cached answer through.
Authentication failures and other error responses keep their original response; the budget check doesn't replace an authentication error with a budget error.
Budgets fail open by default
If a team or gateway budget check fails, the request can continue. However, a
failed check doesn't override a budget violation already detected: a cache hit
still returns 429 if the app's budget check has found an exhausted Block
limit.
To reject requests when Budgets and Costs can't complete its own checks,
enable Fail closed when metering is unavailable (throwOnFailure). This
option is off by default and doesn't change how team or gateway check failures
are handled.
Propagation and accounting delays
Budget changes don't take effect immediately. After editing a budget or moving an app to another team, allow time for the saved settings and usage totals to update. The delay depends on your gateway's cache settings.
Requests already in progress and delays in updating usage totals can take spending past a budget before further requests are blocked.
Monitoring Usage
Each app, team, and the gateway show current usage against their limits:
- Open the Apps & Teams tab and select an app or team
- The Overview tab shows daily and monthly usage—spend, tokens, and requests—with progress against any configured limits
- The same tab's Metrics frame charts request count, token usage, and cost over time; View in Analytics opens the full request-level breakdown scoped to that app or team
Related Resources
- Getting Started - Set up your first AI Gateway project with budget controls
- Managing Teams - Configure team-level budgets
- Managing Apps - Configure app-level limits
- Fallback Models - Serve a cheaper model instead of blocking when a limit is exceeded