Skip to navigation

Usage windows

Refill credits on a schedule, and cap how fast they can be used.

A plan’s credit balance says how much a customer has. A usage window adds time: how much they get each week, how much they may use in a five-hour session, or how fast a pool can be drained. Windows are allowances on the plan, and every one of them is a refill or a cap.

Before you start

kindWhat it does
refillGrants amount credits into a pool at the start of each window. The credits are an ordinary credit grant with source: allowance that expires when the window ends, unless rollover keeps some
capGrants nothing. It limits how many credits can be consumed in the window, whatever the balance is

Refill and cap are separate, so a plan can give 5,000 credits a month and also stop a customer using more than 1,500 of them a week. A plan holds up to ten allowances, and work must have room in every window that applies.

Windows

Each allowance has a window with a type, a duration (ISO 8601, from PT1H to P1Y) and, for fixed windows, an anchor.

typeBehaviorUse it for
fixedResets on a boundary: every duration from the anchorMonthly refills, weekly caps
sessionOpens at the first use after the last one closed, and lasts durationA five-hour session
slidingA cap only. Counts what was used over the trailing duration”No more than 200 credits in any hour”

A fixed window’s anchor is billing_period (the default, the subscription’s period start), subscription_start, calendar (UTC midnight, Monday for a week, the first for a month) or customer. customer resets at the moment the subscription was created, which today is the same as subscription_start, so customers who subscribed at different times reset at different times.

All times are UTC. A refill on a session window grants its credits when the session opens.

Five hours, a week and a month

This plan refills 5,000 credits each billing period, caps use at 1,500 in any five-hour session, and caps use at 3,500 a week:

Config document: plans
{
"plans": [
{
"key": "max_monthly",
"name": "Max",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"recurring_fee": { "amount": 10000, "currency": "usd" },
"pools": [{ "key": "included", "name": "Included usage" }],
"allowances": [
{
"key": "monthly",
"kind": "refill",
"pool": "included",
"amount": "5000",
"window": { "type": "fixed", "duration": "P1M", "anchor": "billing_period" },
"alert_at": ["0.8", "1"]
},
{
"key": "session",
"kind": "cap",
"pool": "included",
"amount": "1500",
"window": { "type": "session", "duration": "PT5H" },
"alert_at": ["0.8", "1"]
},
{
"key": "weekly",
"kind": "cap",
"amount": "3500",
"window": { "type": "fixed", "duration": "P1W", "anchor": "calendar" },
"alert_at": ["0.8"]
}
],
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
}
]
}

The weekly cap has no pool, so it counts consumption from every pool. The session cap counts only the included pool.

A plan sets either included_credits or allowances, not both. included_credits is a monthly refill with no cap, and a request with both returns parameter_invalid.

What counts

A cap counts credits drawn from its pool, after any burn multiplier. Holds count as held, not as used: remaining is reduced, percent_used isn’t. A hold that is released gives the room back. A reversal gives credits back to the window it was drawn from, if that window is still open.

per_member windows

Set scope: per_member on an allowance and each distinct member_id gets its own window. A refill grants amount for each member at the member’s first check() or track() of a window, before that call is measured. That is how a plan adds a weekly allowance for every seat. Without member_id on the call, a per_member allowance doesn’t apply, so send it on check() and track(). See Members, teams and agents.

The members’ refills land in the allowance’s pool, and every member draws on that pool. A refill’s window shows what its member used against amount but doesn’t stop them, so while the pool has credits a member can draw on other members’ refills. To hold each member to amount, add a per_member cap on the same window, which denies a member’s check() once their window is used up. What the refills leave expires with their window and never moves into another pool.

Rollover

A refill on a fixed window can carry unspent credits forward with rollover: none (the default), all or capped with rollover_cap. Rolled credits become a new grant with source: rollover, and last until the end of the next window, or for rollover_expires_after when you set it.

When a cap is full

on_exhausted on a cap chooses what happens when the window has no room:

on_exhaustedResult
block (default)check() denies with the reason allowance_exhausted, and denied_by names the allowance and its resets_at
draw_next_poolThe capped pool is skipped and work draws from the pools after it. A cap on included sends the work to purchased

draw_next_pool needs the cap to name a pool.

Response: CheckResult
{
"object": "check",
"allowed": false,
"reason": "allowance_exhausted",
"customer": "cus_9sF2kq81LmQz",
"credit_type": "ai_credits",
"required": "40",
"available": "3200",
"denied_by": {
"type": "allowance",
"id": "session",
"resets_at": "2026-11-04T18:00:00Z",
"remaining": "10"
},
"affordability": {
"balance": { "available_before": "3200", "available_after": "3160", "shortfall": "0" },
"pools": [
{ "pool": "included", "available_before": "3000", "would_draw": "40", "available_after": "2960" },
{ "pool": "purchased", "available_before": "200", "would_draw": "0", "available_after": "200" }
],
"allowances": [
{
"key": "monthly",
"kind": "refill",
"event_name": null,
"pool": "included",
"on_exhausted": "draw_next_pool",
"member_id": null,
"counted": "40",
"remaining_before": "3000",
"remaining_after": "2960",
"shortfall": "0",
"resets_at": "2026-12-01T00:00:00Z"
},
{
"key": "session",
"kind": "cap",
"event_name": null,
"pool": "included",
"on_exhausted": "block",
"member_id": null,
"counted": "40",
"remaining_before": "10",
"remaining_after": "-30",
"shortfall": "30",
"resets_at": "2026-11-04T18:00:00Z"
},
{
"key": "weekly",
"kind": "cap",
"event_name": null,
"pool": null,
"on_exhausted": "block",
"member_id": null,
"counted": "40",
"remaining_before": "2400",
"remaining_after": "2360",
"shortfall": "0",
"resets_at": "2026-11-09T00:00:00Z"
}
],
"spend_limits": [],
"would_exceed": true,
"reason": "allowance_exhausted"
},
"livemode": false
}

The affordability block lists every window that applies to the work, the monthly refill as well as the two caps, each with the room left and what happens past it. would_exceed is true here because the session cap stops at its cap: it has 10 left and the work counts 40, so shortfall is "30". Only an allowance that stops the work sets it. An allowance that moves the work to the next pool (draw_next_pool) or bills it as overage (an included quantity on a postpaid plan) still lists its shortfall, as the part that moves on or is billed, and leaves would_exceed false. The Checks and holds guide shows both. Allowances apply to prepaid plans, so on a postpaid plan check() lists no windows.

track() never blocks. Work that has already happened is recorded, takes the window past its amount, and carries the warning allowance_exhausted.

Read the meters

GET /v1/customers/{id}/usage_summary returns every window with what was granted, used and held, the share used and the reset time, and names the binding_window, the one that will stop the customer first. See Usage meters. To see which customers are closest to the end of an allowance, GET /v1/reports/allowance_use ranks them by the share used, and percent_used_over keeps only those past a threshold. See Reports and charts.

Alerts

alert_at on an allowance lists decimals from 0 to 1, up to five. The first time a window’s percent_used reaches each one, Runledger sends usage.threshold_reached, once per window. ["0.8", "1"] means 80% and 100%. See Auto top-up and alerts.

What locks

Allowances, like rates, are part of a plan’s pricing. They can change until the first customer subscribes, and after that an update returns plan_locked. Create a new plan and move customers with change_plan, which takes effect at the next period.

Test it

A test clock moves windows. Advance one past a window’s resets_at and the refill grant appears, or the cap clears. The window_cap scenario in the MCP server’s run_scenario tool spends a cap to its limit, shows the denial, then advances past the reset.

Next steps

  • Pools decide which credits a window refills and draws from.
  • Spend limits cap money, where a window caps credits.
  • Usage meters show a customer each window.
  • Recipes puts windows together for common billing models.