budgets.upsert creates it or replaces it, and
unprice.budget(key) takes a handle that spends against it. The handle never creates or changes
the budget.
Keys
The key names what the cap is about. You choose it, and it is unique within the project: up to 128 letters, digits, and: / _ . @ -, starting with a letter or digit.
Units
unit is fixed when the budget is created and cannot change.
Amounts are decimal strings with at most 8 decimal places. The SDK also accepts numbers and rounds
them to 8 places.
Limits
A budget takes up to 16 limits. Each authorization and charge must fit every hard limit.string
required
The cap, in the budget’s unit.
string
required
The period the limit counts over:
hour, day, week, month, or never. Without an anchor,
hour, day, week (ISO, from Monday), and month are UTC calendar periods. never counts for
the life of the budget.integer
Epoch milliseconds. Starts
day, week, and month periods at this instant instead of the UTC
calendar, for example a billing cycle from the customer’s signup date. A month anchored on the 31st
starts on the last day of shorter months.string
default:"hard"
hard denies work that does not fit. soft never denies: it counts usage against the amount, and
its remaining can go negative.string
Unique within the budget. Defaults to the window name. The id fixes the limit’s schedule, so give
a limit with a different schedule a new id.
limits list makes a budget that only counts.
Budgets that end
Give short-lived budgets, such as one per run, aclosesAt in epoch milliseconds.
closesAt, authorize and charge return 409, record is accepted for one more day, and
settle and release keep working. 30 days after it closes, once nothing is left to settle, the
budget is deleted: get returns 404, and an upsert creates it again.
Holds
holds sets how long an authorization may stay open: defaultTtlMs for an authorize that sends no
ttlMs (15 minutes by default), and maxTtlMs, the longest one may ask for (one day by default).
See what happens when a hold expires.
Changing a budget
Each upsert sends the whole definition. A field it leaves out takes its default, so an omittedclosesAt reopens a closing budget, and omitted hold TTLs return to their defaults. Sending the same
definition again changes nothing.
A hard cap below the current consumption plus open holds returns 409.
Who can change a cap
A runtime key can create a budget and tighten it. Loosening it needs a config key, and a runtime key gets 403INSUFFICIENT_PERMISSIONS:
So code that spends under a cap, or an agent that holds its key, cannot lift the cap. Keep the
config key out of the environment that spends. A runtime key also cannot close a budget in the
past: an earlier
closesAt takes effect now.
Reading a budget
result.budget.balance has the least remaining over the hard limits (null without one), the
amount held by open holds and leases, and each limit’s consumed, held, remaining, and
resetsAt. result.history holds up to 12 ended periods for each limited window.
result.budget.operations counts the accepted calls that changed the budget, per verb. It does not
count replays, rejections, or reads.
The full request and response schemas are in the API reference.