# Change flows

A subscription changes through a set of flows. Today most are **queued from the
UI** — the LedgerBee operator app and the customer portal — and the public API
**reads and cancels** queued changes but does not create them. The exception is
cancellation, which has a public endpoint. (A public "queue a change" API is
planned.)

| Flow | What it does | Activates | Where today |
|---|---|---|---|
| Replace plan | Swaps the plan; settles any overlap | at the next billing boundary | UI |
| Direction change | Switches `advance` ⇄ `arrears` | next boundary | UI |
| Cadence change | Switches among the plan's alternative cadences | next boundary (doesn't stack) | UI |
| Products edit | Changes the product set / quantities → new segment | next boundary | UI |
| Pause / resume | Suspends billing, then resumes | immediately / on resume date | UI |
| Cancel / churn | Ends the subscription | per strategy (below) | **Public API** + UI |

Each flow appends a [version or segment](/guides/subscriptions/data-model). A plan
replacement or products edit re-bills the affected partial period and carries its
own [`prorationBehavior`](/guides/subscriptions/proration) to settle it. A queued,
not-yet-active flow is a *scheduled change* you can read or cancel over the API
(below).

## Cancel

`POST /v1/subscriptions/cancel` is the one change flow with a public endpoint:

```bash
curl -X POST https://api.ledgerbee.com/api/v1/subscriptions/cancel \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "id": "0190…", "strategy": "end_of_cycle" }'
```

| Strategy | Effect |
|---|---|
| `end_of_cycle` | Cancels at the end of the current billing period. |
| `immediately` | Cancels now; optionally set `refundBehavior` (below). |
| `specific_date` | Cancels on `effectiveDate` (required for this strategy). |
| `clear_schedule` | Removes a previously scheduled cancellation, leaving it running. |

An immediate cancel can issue a refund via `refundBehavior`:

{/* @codegen subscription-refund — generated by `pnpm docs:generate`; do not edit by hand */}

| refundBehavior | Behavior |
|---|---|
| `none` | No refund is issued. |
| `last_invoice` | Refund the full amount of the last paid invoice. |
| `prorated` | Refund the prorated amount for unused time since the last invoice. |

{/* @codegen-end subscription-refund */}

A scheduled cancellation (`end_of_cycle` / `specific_date`) is itself a queued
change — clear it before it activates with `clear_schedule` or via
scheduled-changes below.

## Read or cancel a queued change

A queued plan replacement, products edit, direction change, or future
cancellation is a *scheduled change* that hasn't activated. List them:

```bash
curl https://api.ledgerbee.com/api/v1/subscriptions/{id}/scheduled-changes \
  -H "x-api-key: YOUR_API_KEY"
```

```json
[
  { "changeId": "0190…", "kind": "replace_plan", "effectiveDate": "2026-07-01", "planId": "0190…", "subscriptionName": "Pro" }
]
```

`kind` is one of `replace_plan`, `edit_products`, `change_direction`, or `churn`.
Cancel one by its `changeId` (`DELETE …/scheduled-changes/{changeId}`); the rest
of the subscription is unaffected and the response is the current state.

`changeId` is **ephemeral** — valid only until the change activates or is
cancelled. Always re-list rather than caching it.
