Payments
KwikSaaS uses Stripe for all payment processing. This guide covers setup, configuration, and testing.Payments are pre-configured. This guide helps you customize plans and connect
your Stripe account.
What’s Included
- Stripe Checkout — Hosted payment page for secure transactions
- Customer Portal — Self-service subscription management
- Webhook sync — Automatic database updates on payment events
- Plan gating — Feature access based on subscription status
- Multiple pricing — Subscriptions (monthly/yearly) and lifetime one-time purchases
Payment Flow
Prerequisites
Stripe Account
Create at stripe.com. Use test mode for development.
Supabase Database
Migrations applied with billing tables.
Stripe Setup
1
Get API keys
2
Create products
Go to Products in Stripe Dashboard:
- Click Add product
- Set name (e.g., “KwikSaaS Standard”)
- Add description
- Set pricing:
- One-time for lifetime access
- Recurring for subscriptions
- Save and copy the Price ID (starts with
price_)
3
Add price IDs to environment
4
Set up webhooks
For local development:Copy the webhook signing secret (For production:
whsec_...) to:- Go to Developers → Webhooks in Stripe Dashboard
- Add endpoint:
https://yourdomain.com/api/webhooks/stripe - Select events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededinvoice.payment_failedpayment_intent.succeeded
- Copy the signing secret to production environment
Plan Configuration
Plans are defined insrc/lib/payments/plans.ts:
Plan Properties
API Endpoints
Create Checkout Session
POST/api/checkout_sessions
Customer Portal
POST/api/customer_portal
Opens Stripe’s billing portal for subscription management.
Webhooks
POST/api/webhooks/stripe
Handles Stripe events and updates database:
Database Tables
user_subscriptions
Stores active subscription state:
one_time_purchases
Stores lifetime/one-time purchases:
payment_history
Audit log of all payments:
Access Control
Check user access with helpers insrc/lib/access.ts:
Feature Keys
Testing
Test Cards
Use these card numbers in Stripe test mode:
Use any future expiry date and any 3-digit CVC.
Testing Webhooks Locally
- Start your dev server:
npm run dev - Start Stripe listener:
- Complete a test checkout
- Check database for new records
Verify Webhook Events
Promo Codes & Coupons
Create in Stripe
- Go to Products → Coupons in Stripe Dashboard
- Create coupon with:
- Percentage or fixed amount off
- Duration (once, repeating, forever)
- Redemption limits
Enable in Plans
Troubleshooting
Checkout returns 400 error
Checkout returns 400 error
Check:
- Price ID is correct and matches Stripe
- Plan exists in
plans.tswith matching price ID - Stripe is in correct mode (test vs live)
Webhook signature verification failed
Webhook signature verification failed
Check: -
STRIPE_WEBHOOK_SECRET matches the endpoint - For local: restart
stripe listen and update secret - For production: verify webhook URL is
correctSubscription not appearing in database
Subscription not appearing in database
Check: 1. Webhook listener is running 2. Check Stripe Dashboard →
Developers → Webhooks for failures 3. Verify database migrations have been
applied 4. Check server logs for errors
Customer portal not working
Customer portal not working
Check:
- User has a
stripe_customer_idinuser_subscriptions - User is authenticated
- Portal is enabled in Stripe Dashboard settings
Going to Production
1
Switch to live mode
Replace test API keys with live keys in production environment.
2
Create production products
Create new products in live mode (test products don’t transfer).
3
Add production webhook
Add endpoint in Stripe Dashboard pointing to production URL.
4
Update price IDs
Set production price IDs in environment variables.
5
Test with real card
Do a small real transaction to verify the flow.
Next Steps
Deployment
Deploy with payments enabled
Access Control
Understand database and RLS policies