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:

StateDescriptionAccess
trialingSubscription is in free trial periodYes
activeSubscription is current and paidYes
past_duePayment failed, in grace periodYes
canceledCancellation scheduled for period endYes
expiredSubscription endedNo

State machine

Lifecycle events

New subscription

When a user subscribes through a checkout link:

  1. Subscription created with active status
  2. current_period_end set based on billing period
  3. next_billing_date scheduled for renewal
  4. Webhook subscription.created sent

Successful renewal

When a subscription renews successfully:

  1. Payment processed on next_billing_date
  2. current_period_end extended by billing period
  3. next_billing_date updated
  4. Webhook subscription.payment_succeeded sent

Failed payment

When a renewal payment fails:

  1. Status changes to past_due
  2. User retains access during grace period
  3. Stash retries payment automatically
  4. Webhook subscription.payment_failed sent

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_succeeded sent

If all retries fail:

  • Status changes to expired
  • Webhook subscription.expired sent
  • User loses access

Cancellation

When a user cancels:

  1. Status changes to canceled
  2. cancel_at_period_end set to true
  3. canceled_at timestamp recorded
  4. Webhook subscription.canceled sent
  5. User keeps access until current_period_end

When the period ends:

  • Status changes to expired
  • Webhook subscription.expired sent

Reactivation

A canceled subscription can be reactivated before it expires:

  1. Call Reactivate Subscription
  2. Status returns to active
  3. cancel_at_period_end set to false
  4. Webhook subscription.reactivated sent

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

FieldDescription
current_period_endWhen the current billing period ends
next_billing_dateWhen the next payment will be attempted
access_end_dateWhen user access expires
trial_endWhen the trial period ends (if applicable)
canceled_atWhen the subscription was canceled

How is this guide?