Subscription Flow
Understand the subscription lifecycle, state transitions, and how subscriptions move between trialing, active, past_due, canceled, and expired states. Learn about billing periods, grace periods, and renewal processing.
This guide explains how subscriptions move through their lifecycle, from creation to expiration.
Subscription states
A subscription is always in one of these states:
| State | Description | Access |
|---|---|---|
trialing | Subscription is in free trial period | Yes |
active | Subscription is current and paid | Yes |
past_due | Payment failed, in grace period | Yes |
canceled | Cancellation scheduled for period end | Yes |
expired | Subscription ended | No |
State machine
Lifecycle events
New subscription
When a user subscribes through a checkout link:
- Subscription created with
activestatus current_period_endset based on billing periodnext_billing_datescheduled for renewal- Webhook
subscription.createdsent
Successful renewal
When a subscription renews successfully:
- Payment processed on
next_billing_date current_period_endextended by billing periodnext_billing_dateupdated- Webhook
subscription.payment_succeededsent
Failed payment
When a renewal payment fails:
- Status changes to
past_due - User retains access during grace period
- Stash retries payment automatically
- Webhook
subscription.payment_failedsent
The default grace period is 48 hours with payment retries at 24h and 48h. During this time, the user keeps access while Stash attempts to recover the payment. Grace period duration and retry schedule can be configured based on your needs.
If payment succeeds during grace period:
- Status returns to
active - Webhook
subscription.payment_succeededsent
If all retries fail:
- Status changes to
expired - Webhook
subscription.expiredsent - User loses access
Cancellation
When a user cancels:
- Status changes to
canceled cancel_at_period_endset totruecanceled_attimestamp recorded- Webhook
subscription.canceledsent - User keeps access until
current_period_end
When the period ends:
- Status changes to
expired - Webhook
subscription.expiredsent
Reactivation
A canceled subscription can be reactivated before it expires:
- Call Reactivate Subscription
- Status returns to
active cancel_at_period_endset tofalse- Webhook
subscription.reactivatedsent
Reactivation is only possible while the subscription is in canceled status. Once it reaches expired, the user must create a new subscription.
Billing period
The period object defines how often the subscription renews:
{
"period": {
"value": 1,
"unit": "month"
}
}Supported units: day, week, month, year
Examples:
- Weekly:
{ "value": 1, "unit": "week" } - Monthly:
{ "value": 1, "unit": "month" } - Quarterly:
{ "value": 3, "unit": "month" } - Yearly:
{ "value": 1, "unit": "year" }
Key dates
| Field | Description |
|---|---|
current_period_end | When the current billing period ends |
next_billing_date | When the next payment will be attempted |
access_end_date | When user access expires |
trial_end | When the trial period ends (if applicable) |
canceled_at | When the subscription was canceled |
How is this guide?