Sign in →

Subscriptions

Manage the full subscription lifecycle — trial, active, past-due, paused, expiring, suspended, cancelled, and reactivated — with Aforo's 10-state machine.

Updated 2026-07-29Suggest edits

Subscriptions

A subscription links a customer to an offering for a billing period. Aforo tracks the full lifecycle with a 10-state machine, automatic dunning, phase history, and version pinning.

Subscription states

Ten states, with the transitions the state machine actually allows:

StateMeaning
CREATEDInitial state. No billing has started.
TRIALINGFree trial in progress. No charges yet.
ACTIVEBilling is live. Usage accrues and invoices generate.
PAST_DUEPayment failed. Dunning is running.
PAUSEDOperator-initiated pause. Usage tracking stops.
EXPIRING_SOONNear end of term. Renewal pending.
SUSPENDEDEscalated from PAST_DUE after dunning is exhausted.
EXPIREDTerm ended without renewal.
CANCELLEDCancelled — but recoverable (see below).
REACTIVATEDA cancelled or expired subscription brought back; transitions on to ACTIVE.
ℹ

CANCELLED is not a dead end. POST /api/v1/subscriptions/{id}/reactivate moves a cancelled or expired subscription to REACTIVATED and then ACTIVE. The only truly one-way exits are the ones you drive deliberately.

Key transitions: ACTIVE can go to PAST_DUE, PAUSED, EXPIRING_SOON, EXPIRED, SUSPENDED, or CANCELLED; PAST_DUE recovers to ACTIVE (on payment) or escalates to SUSPENDED / CANCELLED; EXPIRED can renew back to ACTIVE; EXPIRING_SOON resolves to ACTIVE, EXPIRED, or CANCELLED.

Lifecycle actions

Each action is its own endpoint under /api/v1/subscriptions/{id}:

POST/api/v1/subscriptions/{id}/upgradeMove to a higher offering (proration applies)
POST/api/v1/subscriptions/{id}/downgradeMove to a lower offering
POST/api/v1/subscriptions/{id}/pausePause — usage tracking stops
POST/api/v1/subscriptions/{id}/resumeResume a paused subscription
POST/api/v1/subscriptions/{id}/convert-trialConvert a trial to a paid subscription
POST/api/v1/subscriptions/{id}/extend-trialExtend the trial window
POST/api/v1/subscriptions/{id}/retry-paymentRetry a failed payment
POST/api/v1/subscriptions/{id}/cancelCancel (recoverable via reactivate)
POST/api/v1/subscriptions/{id}/reactivateBring a cancelled/expired subscription back
ℹ

There is no schedule-migration, migrate, or migrate-with-full-proration endpoint. A plan change is an upgrade or downgrade — the subscription ID stays stable and proration is computed automatically. To move subscribers onto a new version of the same rate plan, use POST /api/v1/rate-plan-versions/by-id/{versionId}/migrate.

Dunning

When a payment fails, the subscription moves to PAST_DUE and Aforo retries on a schedule. The default is four retries at days 3, 7, 14, and 30; after the last attempt the subscription escalates to SUSPENDED (or CANCELLED, if the offering overrides the escalation action). The retry schedule and escalation action are set on the rate plan, with a per-offering override.

Phase history

Every state change writes an immutable phase record — when the subscription was in each state, which offering and rate-plan version it was on, and why it transitioned. This is what makes revenue recognition, dispute resolution, and compliance reporting accurate after the fact.

Version pinning

When a subscription is created, Aforo pins the exact rate-plan version it's billing against. Existing subscribers keep that pinned pricing when you publish a new version — they're never silently re-priced. You move them onto the new version explicitly, with the rate-plan-version migrate endpoint above.

ℹ

Deleting a product that has active subscriptions is blocked by the product deletion check — see Products. Cancel or move the subscriptions first; there's no separate "retire" flow that bypasses that guard.