Web service subscription development
A subscription web service is any product where users pay regularly (monthly, yearly) for access to features, content, or data. Technically: managing subscription lifecycle (trial → active → past_due → cancelled), handling failed payments, anti-churn mechanics, and correct feature access based on status.
Subscription lifecycle
trialing (14 days)
↓ automatic payment
active
↓ payment failure
past_due → retry 3–4 times → cancelled
↓ manual cancellation
cancelled → grace period (until period end)
↓
expired
Each transition generates webhook from payment provider. App listens for events and updates subscription status.
Stripe webhook events:
-
invoice.payment_succeeded→ activate/renew -
invoice.payment_failed→ setpast_due, send email -
customer.subscription.deleted→ deactivate access
Dunning management
Dunning is handling failed payments. Stripe Billing has Smart Retries (ML algorithm selects optimal retry time). Configure in billing settings: 3–4 attempts over 7–14 days.
In parallel, send email notifications with card update link. Stripe Billing provides hosted customer portal — page where client updates payment method.
Free trial period
Two approaches:
- Trial without card — user doesn't enter card, must add after trial ends. Less friction, lower conversion.
- Trial with card — card added at signup, charged automatically after trial. Higher conversion, fewer signups.
B2B-SaaS recommends trial with card. B2C and viral products — without card.
Upgrade / Downgrade
Plan change should be instant and account for already-paid period. Stripe handles via proration:
await stripe.subscriptions.update(subscriptionId, {
items: [{ id: itemId, price: 'price_premium_monthly' }],
proration_behavior: 'create_prorations',
});
On upgrade — difference for remaining days charged. On downgrade — difference credited.
Anti-churn: retention mechanics
- Cancellation flow: instead of "Cancel" button — dialog with questions ("Why?"), offer to pause (1–3 months) or discount
-
Email campaigns: series of emails on
past_due, on failed trial conversion, at 30/60/90 days after cancellation - Win-back offers: special offer for cancelled users
Feature access
Access check should be centralized:
// Gate in Laravel
Gate::define('use-advanced-feature', function (User $user) {
return $user->subscription?->active()
&& $user->subscription->plan->hasFeature('advanced');
});
// Usage
$this->authorize('use-advanced-feature');
Timeline
Web service with subscription via Stripe (signup, trial, upgrade/downgrade, portal, basic webhooks): 2–3 months. With advanced pricing, teams, dunning, analytics: 3–5 months.







