> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runledger.co/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runledger.co/_mcp/server.

# Recipes for AI billing models

Each recipe is a [configuration document](/api-reference/how-configuration-works) 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

* The [quickstart](/quickstart), and a sandbox where you can [apply configuration](/api-reference/how-configuration-works).
* The pieces each recipe combines: [usage windows](/guides/usage-windows), [pools](/guides/pools) and [spend limits](/guides/spend-limits).

## 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`**

```json title="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](/guides/pools) and [Usage windows](/guides/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`**

```json title="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`**

```json title="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](/guides/price-rules-and-guardrails) looks the weight up from a property you send on `track()`, and the plan's rate names the rule.

**`Config document: price_rules`**

```json title="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`**

```json title="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`**

```json title="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](/guides/credit-expiry#report-breakage) 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`**

```json title="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}`**

```json title="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](/guides/members-teams-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`**

```json title="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](/guides/customer-view). See [Spend limits](/guides/spend-limits) and [Auto top-up and alerts](/guides/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`**

```json title="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](/guides/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](/guides/members-teams-agents#caps-for-a-person-a-team-or-an-agent).

## Next steps

* [Configuration](/api-reference/how-configuration-works) covers validating, applying and proposing a document.
* [Going live](/going-live/overview) lists what to check before real billing starts.