Skip to navigation

Pools

Keep included, purchased and promotional credits apart, and decide which is spent first.

A pool is a named part of a customer’s balance. Credits sit in a pool, a plan lists its pools in order, and work draws from them in that order. Use pools when credits have different rules but the same unit: included credits that reset each month, purchased credits that last a year, or credits that only some work may use.

Before you start

Pools or credit types

UseWhen
A poolThe credits are worth the same, and differ only in their rules: where they came from, when they expire, which allowance refills them, what they cost to burn
A credit typeThe unit is different: credits and GPU-seconds, or credits in two products. Each prepaid plan has one credit type, and its balances are never added together

Most plans that need “included first, then bought” want pools. A customer with two credit types has two separate balances.

Define pools on a plan

pools lists the pools in drawdown order. An allowance feeds a pool with pool, included_credits and top_up take a pool too, and a credit grant names one.

Config document: plans
{
"plans": [
{
"key": "team_monthly",
"name": "Team",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"recurring_fee": { "amount": 2500, "currency": "usd" },
"per_seat": true,
"pools": [
{ "key": "included", "name": "Included usage" },
{ "key": "purchased", "name": "Extra usage" }
],
"allowances": [
{
"key": "monthly",
"kind": "refill",
"pool": "included",
"amount": "2000",
"scope": "per_member",
"window": { "type": "fixed", "duration": "P1M", "anchor": "billing_period" }
}
],
"top_up": {
"unit_amount_decimal": "1",
"minimum_credits": "1000",
"maximum_credits": "1000000",
"pool": "purchased",
"credits_expire_in": "P1Y"
},
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
}
]
}

A plan with no pools has one, default. Grants made without a pool go to default, or to the plan’s first pool when the grant comes from checkout.

Drawdown order

Work draws from pools in the plan’s order. Inside a pool, credits follow the usual burn order: priority, then soonest expiry, then promotional before paid, then oldest. When a pool runs out, work continues in the next pool. It is denied with insufficient_balance only when every pool is spent.

A cap on a pool can send work onward early, with on_exhausted: draw_next_pool.

Burn multipliers

A multiplier changes how many credits a unit of work costs. Set it on a pool or on a rate, and the two multiply.

WhereExample
pools[].burn_multiplierWork drawn from premium costs 1.6 times the credits
rates[].burn_multiplierA rate for a larger model costs 2 times as much as the base rate
Config document: plans
{
"plans": [
{
"key": "flex_monthly",
"name": "Flex",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"pools": [
{ "key": "included", "burn_multiplier": "1" },
{ "key": "purchased", "burn_multiplier": "1.6" }
],
"rates": [
{ "event_name": "agent.task", "credits_per_unit": "10" },
{ "event_name": "agent.task.large", "credits_per_unit": "10", "burn_multiplier": "2" }
]
}
]
}

A charge is worked out in base credits, then drawn pool by pool. When a pool can’t cover all of it, the covered share is taken at that pool’s multiplier and the rest moves to the next pool at its own. With 4 credits left in included (multiplier 1), a 10-credit task takes 4 from included and the remaining 6 base credits cost 9.6 from purchased. required on a check is the charge in base credits, and the ledger entries show the credits actually drawn from each pool.

For a multiplier that depends on the model or the request, use a price rule on the rate instead. A rate takes either price_rule or burn_multiplier.

Read balances

GET /v1/customers/{id}/balances returns each balance with a pools array, and the ledger records the pool on every entry. GET /v1/ledger_entries filters by pool.

Response: Balance
{
"object": "balance",
"customer": "cus_9sF2kq81LmQz",
"credit_type": "ai_credits",
"posted": "4870",
"held": "40",
"limit": "0",
"available": "4830",
"pools": [
{ "pool": "included", "posted": "570", "held": "40", "available": "530" },
{ "pool": "purchased", "posted": "4300", "held": "0", "available": "4300" }
],
"as_of": "2026-11-04T13:12:09Z",
"livemode": false
}

posted, held and available at the top are the sums. Holds draw from the pools in order, like work does.

Rules

  • Pool keys are unique on a plan. A grant to a pool the customer’s plan doesn’t list is parameter_invalid.
  • pools, allowances and burn multipliers lock with the rest of the plan’s pricing once a customer subscribes.
  • Two pools never mix their expiry. A pool’s soonest expiry shows as next_expiry in the usage summary.
  • A per_member refill adds amount to its pool for each member, at the member’s first call of a window. The members share that pool, and what is left expires with the window, so it never moves to another pool, such as purchased. A per_member cap holds each member to amount.
  • Spend limits can name a pool, so you can cap spending on purchased credits alone. See Spend limits.

Next steps