Skip to navigation

Recipes for AI billing models

Plans, pools, windows and limits put together for the models AI products use.

Each recipe is a configuration document you can validate with a dry run, apply in the sandbox and propose for live. Prices here are placeholders. Use your own.

Before you start

Credits that refill every month

Customers pay a monthly fee and get credits that reset each period. Unused credits roll over, up to a limit, and top-ups last a year.

Config document: plans
{
"plans": [
{
"key": "starter_monthly",
"name": "Starter",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"recurring_fee": { "amount": 2000, "currency": "usd" },
"pools": [{ "key": "included" }, { "key": "purchased" }],
"allowances": [
{
"key": "monthly",
"kind": "refill",
"pool": "included",
"amount": "2000",
"window": { "type": "fixed", "duration": "P1M", "anchor": "billing_period" },
"rollover": "capped",
"rollover_cap": "500",
"alert_at": ["0.8", "1"]
}
],
"top_up": {
"unit_amount_decimal": "1",
"minimum_credits": "1000",
"maximum_credits": "100000",
"pool": "purchased",
"credits_expire_in": "P1Y"
},
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
}
]
}

Included credits are drawn first and purchased credits after. See Pools and Usage windows.

A weekly cap on top of a monthly allowance

A customer gets 5,000 credits a month, and can’t use more than 1,500 in a week, so a burst of work early in the month doesn’t empty it. When the cap is hit, work waits until the week resets.

Config document: plans
{
"plans": [
{
"key": "pro_capped",
"name": "Pro",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"recurring_fee": { "amount": 5000, "currency": "usd" },
"allowances": [
{
"key": "monthly",
"kind": "refill",
"amount": "5000",
"window": { "type": "fixed", "duration": "P1M", "anchor": "billing_period" }
},
{
"key": "weekly",
"kind": "cap",
"amount": "1500",
"window": { "type": "fixed", "duration": "P1W", "anchor": "customer" },
"on_exhausted": "block",
"alert_at": ["0.8", "1"]
}
],
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
}
]
}

anchor: customer gives each customer their own reset time. When check() denies, denied_by.resets_at says when to try again. A five-hour session cap is the same thing with "type": "session" and "duration": "PT5H".

A multiplier by plan tier

Higher tiers get more work for each credit. Every plan shares the same rates, and the tiers differ only in the pool’s burn multiplier.

Config document: plans
{
"plans": [
{
"key": "tier_basic",
"name": "Basic",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"recurring_fee": { "amount": 2000, "currency": "usd" },
"pools": [{ "key": "included", "burn_multiplier": "1" }],
"included_credits": { "amount": "2000", "pool": "included" },
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
},
{
"key": "tier_plus",
"name": "Plus",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"recurring_fee": { "amount": 6000, "currency": "usd" },
"pools": [{ "key": "included", "burn_multiplier": "0.6" }],
"included_credits": { "amount": "6000", "pool": "included" },
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
}
]
}

A task costs 10 credits on Basic and 6 on Plus. Plans lock once subscribed, so a customer moves tiers with change_plan, which takes effect at the next period.

Weight by model

When a heavier model should cost more credits, price by the model. A table price rule looks the weight up from a property you send on track(), and the plan’s rate names the rule.

Config document: price_rules
{
"price_rules": [
{
"key": "task_by_model",
"name": "Task credits by model",
"method": "table",
"currency": "usd",
"credit_value_decimal": "1",
"rows": [
{ "dimensions": { "model": "small" }, "unit_amount_decimal": "5" },
{ "dimensions": { "model": "standard" }, "unit_amount_decimal": "10" },
{ "dimensions": { "model": "large" }, "unit_amount_decimal": "40" }
]
}
]
}

With credit_value_decimal of "1", each row’s amount is its credit weight. The plan’s rate names the rule, { "event_name": "agent.task", "price_rule": "task_by_model" }, and the rule’s currency must be the plan’s. Send properties: { "model": "large" } on check() and track(). For a flat weight on one event name, set burn_multiplier on the rate instead.

Prepaid commit

A customer prepays for a year of usage under a contract. Grant the credits with an expiry and a cost basis, and set an overdraft so work doesn’t stop the moment the commitment is spent. A top-up at the plan’s price covers the rest.

POST /v1/credit_grants
{
"external_customer_id": "org_123",
"credit_type": "ai_credits",
"amount": "1200000",
"category": "paid",
"cost_basis": { "amount_decimal": "0.8", "currency": "usd" },
"pool": "commit",
"priority": 10,
"expires_at": "2027-11-04T00:00:00Z",
"metadata": { "contract": "ctr_2026_0187" }
}

The plan lists the pool:

Config document: plans
{
"plans": [
{
"key": "enterprise_commit",
"name": "Enterprise",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "year",
"credit_type": "ai_credits",
"pools": [{ "key": "commit" }, { "key": "purchased" }],
"overdraft_limit": "50000",
"top_up": {
"unit_amount_decimal": "1",
"minimum_credits": "10000",
"maximum_credits": "5000000",
"pool": "purchased",
"auto": { "allowed": true }
},
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
}
]
}

The grant’s cost_basis makes the prepayment deferred revenue until it is used or expires, and the breakage report shows what lapsed. Runledger doesn’t bill a shortfall against the commitment at the end of the term.

Per seat, plus pooled credits

Each seat’s first call of a week adds a weekly allowance to the seat pool, and the organization shares a pool of purchased credits.

Config document: plans
{
"plans": [
{
"key": "seats_monthly",
"name": "Team",
"billing_mode": "prepaid",
"currency": "usd",
"interval": "month",
"credit_type": "ai_credits",
"per_seat": true,
"recurring_fee": { "amount": 3000, "currency": "usd" },
"pools": [{ "key": "seat" }, { "key": "shared" }],
"allowances": [
{
"key": "seat_weekly",
"kind": "refill",
"pool": "seat",
"amount": "1000",
"scope": "per_member",
"window": { "type": "fixed", "duration": "P1W", "anchor": "calendar" }
}
],
"top_up": {
"unit_amount_decimal": "1",
"minimum_credits": "5000",
"maximum_credits": "1000000",
"pool": "shared"
},
"rates": [{ "event_name": "agent.task", "credits_per_unit": "10" }]
}
]
}

recurring_fee is per seat. Set the seat count when you create the subscription with quantity, and change it with PATCH /v1/subscriptions/{id}:

PATCH /v1/subscriptions/{subscription_id}
{ "quantity": 12 }

A new quantity applies to the recurring fee from the next period. Send member_id on every call, so each seat’s refill arrives with its first call of the week. Calls draw from the seat pool, which holds every active seat’s refill, and then from the shared pool. What the seat pool leaves expires with its window, so it never adds to the shared pool. To hold each seat to its 1,000 credits, add a per_member cap on the same window. See Members, teams and agents.

Pay as you go with a safety net

Customers buy credits as they need them, a top-up buys more automatically, and each customer has a monthly spend limit they can lower.

Config document: spend_limits
{
"spend_limits": [
{
"key": "payg_monthly",
"applies_to": { "plan": "payg" },
"period": { "duration": "P1M", "anchor": "billing_period" },
"amount": { "amount": 100000, "currency": "usd" },
"ceiling": { "amount": 1000000, "currency": "usd" },
"action": "block",
"alert_at": ["0.75", "1"]
}
]
}

Customers set their own auto top-up and a lower limit from the customer view. See Spend limits and Auto top-up and alerts.

Postpaid with included usage

Invoice customers monthly with some usage included. Units past the included quantity are billed at a different rate, as overage lines.

Config document: plans
{
"plans": [
{
"key": "invoice_monthly",
"name": "Invoiced",
"billing_mode": "postpaid",
"currency": "usd",
"interval": "month",
"recurring_fee": { "amount": 9900, "currency": "usd" },
"credit_limit": { "amount": 500000, "currency": "usd" },
"rates": [
{
"event_name": "agent.task",
"unit_amount_decimal": "95",
"included_quantity": "1000",
"overage_unit_amount_decimal": "120"
}
]
}
]
}

The usage summary shows the included quantity as a window with kind: included.

Teams with budgets

Give each team a budget inside one customer, and each agent a daily cap. See Members, teams and agents.

Next steps

  • Configuration covers validating, applying and proposing a document.
  • Going live lists what to check before real billing starts.