---
title: Plans & Variants
description: How a sellable plan is put together — variants, credit grants, and what retiring one actually does.
order: 13
---

# Plans & Variants

A plan is the thing you sell. A variant is one way to buy it. Everything a customer actually gets — credits, trial length, billing cycle — hangs off the variant, not the plan.

> **Mental Model:** A plan is **the name on the box**; a variant is **one way to buy what is inside**. Customers never subscribe to a plan — they subscribe to a variant, and every commercial term they get (cycle, trial, credits, entitlements) hangs off that variant.

## Quick Take

- Customers subscribe to a **variant**, never to a plan
- The variant carries billing cycle, billing mode, trial days, and the overdue settings
- Credit grants and entitlements attach to the **variant**
- `grant_interval` takes a keyword <em>or</em> an ISO 8601 duration like `PT5H` — minimum 5 minutes
- Retiring stops **new** subscriptions; existing ones keep running untouched

## Diagram

A plan holds one or more variants. Each variant carries the billing terms, its own credit grants, and its own entitlements. Customers subscribe to a variant.

```mermaid
flowchart TD
    P[Plan · name, status, is_default] --> V1[Variant · monthly, prepaid]
    P --> V2[Variant · yearly, prepaid]
    V1 --> G1[Credit grant]
    V1 --> E1[Entitlements]
    V2 --> G2[Credit grant]
    V2 --> E2[Entitlements]
    C[Customer] -->|subscribes to| V1
```

## The shape

```
Plan  "Pro"
 ├── Variant  monthly, prepaid, 14-day trial
 │    ├── Credit grant   50,000 credits every billing_cycle
 │    └── Entitlements   seats: 10, api_access: true
 └── Variant  yearly, prepaid, 14-day trial
      ├── Credit grant   700,000 credits every billing_cycle
      └── Entitlements   seats: 25, api_access: true
```

Customers subscribe to a **variant**, never to a plan. The plan is the name on the box.

## The plan

A plan holds very little: a name, a status, and whether it is your default.

| Field | Meaning |
|---|---|
| `name` | What you call it. |
| `status` | `active` or `retired`. |
| `is_default` | The plan new customers land on when you have not chosen one. |

You cannot retire your default plan. Make another plan the default first, then retire the old one.

## The variant

The variant carries the commercial terms.

| Field | Meaning |
|---|---|
| `billing_cycle` | `daily`, `weekly`, `monthly`, `yearly`, or `one_time`. |
| `billing_mode` | `prepaid` (credits up front) or `postpaid` (usage billed after). |
| `trial_days` | Days of trial. Above zero, a new subscription starts in `trialing`. |
| `renewal_due_days` | How long a renewal can sit unpaid before the subscription goes overdue. |
| `grace_period_days` | How long an overdue subscription keeps working. |
| `allow_usage_while_overdue` | Whether an overdue customer can keep spending. |
| `status` | `active` or `retired`. |

## Credit grants

A grant is a standing instruction: give this customer this many credits, this often.

| Field | Meaning |
|---|---|
| `credits` | Millicredits per grant. |
| `grant_interval` | How often. See below. |
| `grant_type` | `recurring`, `one_time`, or `trial`. |
| `expires_after_seconds` | How long each granted block lasts. Empty means it never expires. |
| `accumulation_cap` | The most that can pile up unspent. |
| `rollover_percentage` | How much unspent credit carries into the next period. |
| `max_rollover_cycles` | How many periods credit can keep rolling. |

### Grant intervals

`grant_interval` takes one of five keywords:

- `daily`
- `weekly`
- `monthly`
- `billing_cycle` — grant on each renewal, matching the variant's cycle
- `on_activation` — grant once, when the subscription starts

Or it takes an **ISO 8601 duration**, which is any value starting with `P`:

| Value | Means |
|---|---|
| `PT5H` | Every 5 hours |
| `PT4H` | Every 4 hours |
| `P3D` | Every 3 days |
| `P1W` | Every week |

Custom intervals exist for products that refill on a clock rather than a calendar — a five-hour usage window, for example. The smallest allowed custom interval is **5 minutes**. Anything shorter is rejected, because it would turn the scheduler into a hot loop.

Anything that does not start with `P` and is not one of the five keywords is rejected.

## Entitlements

Grants give credits. Entitlements give everything else: seat counts, feature flags, fixed limits. They attach to the variant too.

That is its own topic — see [Plan-Variant Entitlements](/docs/concepts/plan-variant-entitlements).

## Retiring a plan or a variant

Set `status` to `retired`. Here is exactly what that does, and what it does not do.

**It stops new subscriptions.** Subscribing to a retired variant is refused. This is the point of retiring: the plan is no longer for sale.

**It does not touch existing subscriptions.** Customers already on that variant keep their subscription, keep their grants, and keep renewing. Nothing is cancelled and nothing is migrated. If you want existing customers moved, move them yourself with an upgrade or downgrade.

**It does not delete anything.** The plan, its variants, and its grants all still exist. Retiring is a visibility change, not a deletion.

## The catalog is shared across environments

This is the part that catches people. Plans, variants, and grants have **no environment**. There is one copy, and both sandbox and live read it.

Retire a plan while testing in sandbox and you have retired it in live. Change a grant amount in sandbox and live customers get the new amount on their next renewal.

Read [Environments & the Shared Catalog](/docs/concepts/environments) before you edit a plan you did not create today.

## Building one

The order matters, because each step attaches to the one before it.

1. Create the plan.
2. Add a variant to the plan.
3. Add a credit grant to the variant.
4. Add entitlements to the variant.
5. Subscribe a customer to the variant.

The dashboard walks this in one flow under **Plans**. Every step is also a single API call if you would rather script it.

## Common Mistakes

**✗ Don't expect retiring a plan to move or cancel its subscribers**

Retiring only stops new subscriptions. Existing customers keep their subscription and keep renewing. Migrate them yourself with an upgrade or downgrade.

**✗ Don't edit a plan in sandbox to see what happens**

The catalog is shared. There is one copy of every plan, variant, and grant, and live reads the same row you just changed.

**✗ Don't use a custom grant interval shorter than 5 minutes**

It is rejected. Anything faster would turn the grant scheduler into a hot loop.

**✗ Don't try to retire your default plan**

It is refused. Make another plan the default first, then retire the old one.

## Related

- [Plan-Variant Entitlements](/docs/concepts/plan-variant-entitlements) — Attach metrics to variants with typed values.
- [Subscriptions](/docs/concepts/subscriptions) — The lifecycle a customer moves through once subscribed.
- [Subscription Overrides](/docs/concepts/subscription-overrides) — Give one customer a different value without a new plan.
- [Environments & the Shared Catalog](/docs/concepts/environments) — Why editing a plan in sandbox changes it in live.
