Skip to content

Latest commit

 

History

History
123 lines (77 loc) · 4.52 KB

File metadata and controls

123 lines (77 loc) · 4.52 KB

Payment Setup

Launchpad supports two billing providers for subscriptions: Stripe and LemonSqueezy. The e-commerce shop module uses Stripe only (one-time purchases, not subscriptions).

Set PAYMENT_PROVIDER=stripe or PAYMENT_PROVIDER=lemonsqueezy in your .env.local. If you don't set it, it defaults to Stripe.


Stripe — Subscriptions (SaaS)

1. Create your products

In the Stripe Dashboard, create two products: Pro and Team. For each, create two prices — one monthly, one yearly — that match the amounts defined in src/user-control/plans-config.ts:

  • Pro: $29/month, $279/year
  • Team: $79/month, $759/year

2. Copy the IDs to your .env.local

STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...

STRIPE_PRO_MONTHLY_PRICE_ID=price_...
STRIPE_PRO_YEARLY_PRICE_ID=price_...
STRIPE_PRO_PRODUCT_ID=prod_...

STRIPE_TEAM_MONTHLY_PRICE_ID=price_...
STRIPE_TEAM_YEARLY_PRICE_ID=price_...
STRIPE_TEAM_PRODUCT_ID=prod_...

3. Set up the webhook

In the Stripe Dashboard, go to Developers → Webhooks → Add endpoint.

  • Production endpoint URL: https://yourdomain.com/api/webhooks/stripe
  • For local testing, use the Stripe CLI: stripe listen --forward-to localhost:3000/api/webhooks/stripe

Select these events:

  • checkout.session.completed
  • customer.subscription.updated
  • customer.subscription.deleted

Copy the Signing secret (starts with whsec_) into STRIPE_WEBHOOK_SECRET.

4. Test

Use Stripe's test card: 4242 4242 4242 4242, any future expiry, any CVC. After a successful test checkout, the subscription status should update in your database and appear on the billing page.

To test cancellation: go through a test checkout, then use the customer portal to cancel. The customer.subscription.updated webhook will fire with cancel_at_period_end: true.


LemonSqueezy — Subscriptions (alternative)

1. Set the provider

PAYMENT_PROVIDER=lemonsqueezy

2. Create your products

In your LemonSqueezy dashboard, create a Pro product and a Team product. For each, create monthly and yearly variants. Note the variant IDs (not product IDs) for each.

3. Copy the IDs

LS_API_KEY=...
LS_STORE_ID=...

LS_PRO_MONTHLY_VARIANT_ID=...
LS_PRO_YEARLY_VARIANT_ID=...
LS_PRO_PRODUCT_ID=...

LS_TEAM_MONTHLY_VARIANT_ID=...
LS_TEAM_YEARLY_VARIANT_ID=...
LS_TEAM_PRODUCT_ID=...

4. Set up the webhook

In LemonSqueezy → Settings → Webhooks → Add webhook:

  • Endpoint URL: https://yourdomain.com/api/webhooks/lemonsqueezy
  • Select events: subscription_created, subscription_updated, subscription_cancelled, subscription_expired, subscription_payment_success, subscription_payment_failed

Copy the signing secret into LS_WEBHOOK_SECRET.

LemonSqueezy billing portal note: Unlike Stripe, LemonSqueezy doesn't have a "create portal session" API call. Instead, every subscription webhook includes a signed customer portal URL. Launchpad stores this URL when the subscription is created and uses it on the billing page. This means the billing portal link is only available after at least one subscription webhook has been received.


Stripe — One-time purchases (E-commerce shop)

The shop module uses a completely separate checkout flow from subscription billing. Products are created through your dashboard (/dashboard/products), not pre-configured in the codebase.

You only need:

STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

These can be the same values as your subscription Stripe keys — both flows share the same webhook endpoint. The webhook handler dispatches internally based on whether metadata.orderId (shop checkout) or metadata.userId (subscription checkout) is present.


Switching between Stripe and LemonSqueezy

Change PAYMENT_PROVIDER and restart. No code changes needed. You can keep both sets of environment variables populated and switch freely between them.


Going live

When you're ready to move from test mode to live:

  1. Replace sk_test_... keys with sk_live_... keys in your production environment
  2. Update your webhook endpoints in the Stripe/LemonSqueezy dashboard to point at your production URL
  3. Create new webhook entries (or update existing ones) with the production URLs — the signing secrets will change
  4. Run a real end-to-end transaction with a real card to verify everything is working

Keep test mode active in your local .env.local — only the production environment should ever use live keys.