Billing
Billing providers and webhook setup.
Billing
SaaS Starter supports multiple billing providers switchable via a single environment variable.
Provider selection
# .env
BILLING_PROVIDER=stripe # stripe | paddle
| Provider | Best for | Env var prefix |
|---|---|---|
| Stripe | Most flexibility, global cards, developer-friendly | STRIPE_ |
| Paddle | Merchant of Record, EU VAT & tax handled automatically | PADDLE_ |
| LemonSqueezy | Fast digital product checkout | LEMONSQUEEZY_ |
| Polar | Merchant-of-record and subscriptions | POLAR_ |
Stripe setup
STRIPE_SECRET_KEY=your-stripe-secret-key
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret
STRIPE_PUBLISHABLE_KEY=your-stripe-publishable-key
Run the Stripe setup script to sync products/prices:
pnpm run setup:stripe
# or interactively:
pnpm cli init
Paddle setup
PADDLE_API_KEY=your-paddle-api-key
PADDLE_WEBHOOK_SECRET=your-paddle-webhook-secret
PADDLE_CLIENT_TOKEN=your-paddle-client-token
Webhook handling
Provider webhook endpoints:
POST /api/webhooks/stripe
POST /api/webhooks/paddle
POST /api/webhooks/lemonsqueezy
POST /api/webhooks/polar
Events handled automatically:
subscription.created→ activate plan, emitsubscription:createdeventsubscription.updated→ update plan/statussubscription.canceled→ downgrade, emitsubscription:canceledeventpayment.succeeded→ add AI credits (if configured)payment.failed→ notify user
Plan configuration
Plans are defined in packages/shared/src/plans.ts:
export const PLANS = {
free: {
limits: {
aiTokensPerMonth: 50_000,
teamMembers: 3,
projects: 5,
},
features: ['aiChat', 'analytics'],
},
pro: { ... },
business: { ... },
}
The CLI pnpm cli init walks you through billing provider selection and
automatically runs the appropriate setup script.