Setting Up Stripe Billing in Next.js: The Complete Guide
A comprehensive guide to integrating Stripe subscriptions, webhooks, and customer portal in your Next.js SaaS application.
Why Stripe for SaaS Billing?
Stripe is the industry standard for SaaS billing. It handles subscriptions, invoicing, tax calculation, payment method management, and provides a customer portal — all through a robust API.
But integrating Stripe properly is more complex than most tutorials suggest. You need to handle:
- Subscription lifecycle (create, upgrade, downgrade, cancel, reactivate)
- Webhook events (payment succeeded, failed, subscription updated)
- Idempotent processing (no duplicate charges)
- Data reconciliation (keeping your database in sync with Stripe)
- Edge cases (failed payments, disputed charges, prorations)
The Webhook Challenge
The most critical part of Stripe integration is webhook handling. Stripe sends events to your server when things happen — payments succeed, subscriptions renew, cards expire. Your webhook handler needs to:
- Verify the signature to ensure the event is from Stripe
- Process idempotently so redelivered events don't cause duplicate actions
- Handle all relevant events including edge cases
- Update your database to reflect the current state
What ShipKit Provides
ShipKit includes a complete Stripe integration with:
- Subscription management: Create, cancel, reactivate, upgrade/downgrade
- Webhook handler: Processes 15+ event types with idempotent handling
- Customer Portal: One-click access for users to manage their subscription
- Daily reconciliation: Automated job that syncs your database with Stripe
- Pricing plans: Admin CRUD for managing plans, add-ons, and lifetime deals
- Usage tracking: Metered billing support for usage-based pricing
Key Architecture Decisions
Store Stripe IDs in Your Database
Always store stripeCustomerId and stripeSubscriptionId on your user/organization models. This lets you quickly look up Stripe data without additional API calls.
Use Webhook Events as Source of Truth
Don't rely on client-side callbacks for payment confirmation. Always use webhook events to update subscription status in your database.
Implement Reconciliation
Network issues can cause missed webhooks. A daily reconciliation job that compares your database with Stripe ensures data consistency.
Conclusion
Stripe billing is a critical piece of SaaS infrastructure that's deceptively complex to implement correctly. ShipKit's battle-tested implementation handles all the edge cases so you can start charging customers from day one.