How PaywallProject handles various subscription paths.
Assume today is June 12 and the subscriber’s current period ends June 30.
| Scenario | Stripe action | New expiry | Example |
|---|---|---|---|
| Recurring → Recurring (upgrade) | In-place price update | Unchanged — stays at current period_end |
Was expiring Jun 30 → still expires Jun 30 Prorated charge issued immediately for price difference
|
| Recurring → Recurring (downgrade) | In-place price update | Unchanged — stays at current period_end |
Was expiring Jun 30 → still expires Jun 30 Prorated credit applied to next invoice, not refunded
|
| Recurring → Non-recurring | Immediate cancel + new one-time intent | Now + level interval (remaining time lost) |
Was expiring Jun 30 → expiry deleted on cancel → new expiry Jul 12 (30-day level) 18 days of remaining access forfeited — no credit
|
| Non-recurring → Recurring | New subscription | Stripe current_period_end (fresh billing cycle) |
Paid Jun 12 → expires Jul 12 (monthly level) Clean start, no interaction with old one-time expiry
|
| Non-recurring → Non-recurring | New one-time intent | Existing expiry + level interval (time stacks if still active) |
Current expiry Jun 30 → pays for 30-day level on Jun 12 → new expiry Jul 30 If already expired: now + interval (Jul 12)
|
| Recurring (active) → Trial recurring | Immediate cancel + new checkout with trial | Trial end date (from Stripe current_period_end) |
Was expiring Jun 30 → cancelled → 14-day trial starts Jun 12 → expires Jun 26 Remaining time on old plan forfeited; subscriber gets full trial
|
| Recurring (trialing) → Recurring (no trial) | Immediate cancel + new subscription | New current_period_end from fresh subscription |
Trial was ending Jun 26 → cancelled → paid monthly starts Jun 12 → expires Jul 12 Trial cancelled immediately, billing starts now
|
| Recurring (trialing) → Trial recurring | Immediate cancel + new checkout with trial | New trial end date |
Trial A ending Jun 26 → cancelled → Trial B starts Jun 12 → expires Jun 26 Gets a full fresh trial on the new level
|
| Past due → anything | Immediate cancel + new checkout | Set fresh on completion of new checkout |
Webhook already set expiry to Jun 1 (period_start) → cancel deletes it → new sub expiry Jul 12 Access was already revoked; fresh start on payment
|