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
| Status | Description | Can User Access Service |
|---|---|---|
pending | Checkout initiated, awaiting payment | No |
trialing | In trial period | Yes (in unlimited sub mode) |
active | Paid and active | Yes |
canceling | User has canceled, but current period hasn't ended | Yes (until period ends) |
canceled | Canceled and period has ended | No |
expired | Expired (payment failed or naturally ended) | No |
paused | Paused by payment platform, prevents usage while billing stops | No |
past_due | Payment overdue, system treats as expired | No |
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_startfield - 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_typeandpending_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 becomescanceled - Cancel immediately: Status becomes
canceledright 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:
- Renewal success Webhook received (e.g.,
invoice.paid) - System updates
current_period_startandcurrent_period_end - If there's a pending downgrade plan, it's applied at this point
- In Quota Subscription mode, monthly quota is reset
If renewal fails:
- Payment failure Webhook received (e.g.,
invoice.payment_failed) - System marks the subscription as
expired, immediately stopping service - The payment provider backend continues retrying the charge
- 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
updateSubscriptionPeriodonly allows periods to move forwardexpireSubscriptionchecks whethercurrent_period_endhas passedmarkSubscriptionCanceledonly allows transitions fromactive/trialing/canceling