logoPay4SaaS
Core Concepts

Subscription Lifecycle

A subscription isn't just "pay and done" — trial, activation, renewal, upgrade/downgrade, cancellation, expiry — each step has its own status and handling logic. Pay4SaaS manages this entire lifecycle for you.

State Flow

                      ┌─────────┐
                      │ pending │  ← Checkout initiated
                      └────┬────┘

                ┌──────────┴──────────┐
                ▼                     ▼
          ┌──────────┐          ┌──────────┐
          │ trialing │──payment─▶│  active  │◀── Renewal success / Resume
          └──────────┘          └────┬─────┘

                 ┌───────────┬───────┼───────┬───────────┐
                 ▼           ▼       ▼       ▼           ▼
           ┌───────────┐ ┌────────┐ ┌──────┐ ┌────────┐
           │ canceling │ │ paused │ │expired│ │past_due│→ Treated as expired
           └─────┬─────┘ └────────┘ └──────┘ └────────┘

                 │ Period ends

           ┌──────────┐
           │ canceled │
           └──────────┘

Status Descriptions

StatusDescriptionCan User Access Service
pendingCheckout initiated, awaiting paymentNo
trialingIn trial periodYes (in unlimited sub mode)
activePaid and activeYes
cancelingUser has canceled, but current period hasn't endedYes (until period ends)
canceledCanceled and period has endedNo
expiredExpired (payment failed or naturally ended)No
pausedPaused by payment platform, prevents usage while billing stopsNo
past_duePayment overdue, system treats as expiredNo

Trial Period

After configuring a trial period (see Pricing Models), users can try the service for free on their first subscription.

Key rules:

  • Each user can only trial once — the system tracks this via the trial_start field
  • Users who have already trialed will automatically use the no-trial product ID at checkout
  • During trial, users can access the service normally in Unlimited Subscription mode
  • In Quota Subscription mode, there's no trial concept, but you can grant bonus credits for users to try
  • After the trial ends, payment is charged automatically — if successful, status becomes active

Upgrades & Downgrades

The system determines upgrade vs downgrade by comparing actual prices: new price > current price = upgrade, otherwise = downgrade.

Upgrade (Immediate Effect)

  • New plan takes effect immediately
  • Payment provider automatically calculates the prorated difference
  • In Quota Subscription mode, quota resets to the new plan

Downgrade (Next Cycle)

  • Current cycle remains unchanged, retaining the original plan's benefits
  • System writes pending_plan_type and pending_plan_billing_cycle
  • When the next renewal Webhook arrives, the downgrade is automatically applied
  • In Quota Subscription mode, current cycle retains the original quota

The frontend can check pending downgrade info via status.details:

const { status } = useAccess()

if (status.details.pendingPlanType) {
  console.log(`Will switch to: ${status.details.pendingPlanType} next cycle`)
  console.log(`Effective at: ${status.details.pendingPlanEffectiveAt}`)
}

Cancellation & Resume

Cancellation

There are two types of cancellation:

  • Cancel at period end (default): Status becomes canceling, user can still use the service until the period ends, then becomes canceled
  • Cancel immediately: Status becomes canceled right away, access revoked instantly

Resume

Users in canceling status (period hasn't ended yet) can undo the cancellation:

  • Status reverts to active
  • Cancellation-related fields are cleared
  • Normal billing continues

Renewal

Renewal is automatic. The payment provider charges automatically before each billing cycle ends and notifies the system via Webhook:

  1. Renewal success Webhook received (e.g., invoice.paid)
  2. System updates current_period_start and current_period_end
  3. If there's a pending downgrade plan, it's applied at this point
  4. In Quota Subscription mode, monthly quota is reset

If renewal fails:

  1. Payment failure Webhook received (e.g., invoice.payment_failed)
  2. System marks the subscription as expired, immediately stopping service
  3. The payment provider backend continues retrying the charge
  4. If a subsequent charge succeeds, the success Webhook auto-restores the subscription

Duplicate Subscription Handling

If a user initiates a new subscription while already having one:

  • Same plan: Extends the expiry date (stacks the new period onto the existing subscription)
  • Different plan: Cancels the old subscription and activates the new one

Out-of-Order Protection

Payment provider Webhooks may arrive out of order (e.g., "cancel" arriving before "activate"). The system guards against this with:

  • Each status change operation checks whether the current state allows the transition
  • updateSubscriptionPeriod only allows periods to move forward
  • expireSubscription checks whether current_period_end has passed
  • markSubscriptionCanceled only allows transitions from active/trialing/canceling

On this page