Decide your subscription model and pricing
1-2 days
checkout.session.completed
Mark subscription active in DB. Idempotency key: session.id.
Card 4242 → checkout success → subscription active
Standard happy path.
Set up the Stripe account and create products + prices
1 day
customer.subscription.updated
Sync plan changes. Watch for status: trialing/active/past_due/canceled.
Card 4000 0000 0000 0341 → fails authentication
3DS challenge required. Confirm UI shows. Confirm DB stays inactive on cancel.
Build the checkout flow (Stripe Checkout vs Elements)
2-3 days
customer.subscription.deleted
Subscription canceled. Set DB.status=canceled, retain access until period_end.
Subscription past_due → automatic retry → eventual cancel
Stripe retries 4x. Confirm cancellation email triggers.
Set up webhook handling (the hard part)
3-5 days
invoice.payment_failed
Email customer + retry per Stripe dunning. After 4 fails, downgrade.
Webhook signature mismatch → 401 + log
Confirm we reject + alert ops.
Reconcile Stripe state with your DB
1-2 days
Set up Stripe Tax (or sales tax / VAT / GST)
1-2 days
Build the Customer Portal (or roll your own)
1 day
Configure dunning (failed payment recovery)
1 day
Switch to live mode + go to production
1 day
Set up monitoring, reconciliation, and revenue dashboards
1 week