Skip to content
Launch Kit logo

Connect

Stripe

Add a price, point the webhook at Launch Kit, and keep plan copy in config.ts. Checkout and access are already wired.

The pricing card calls ButtonCheckout. That hits /api/stripe/create-checkout, opens Stripe Checkout, and comes back to the page the customer was on. The webhook then writes customer_id, price_id, and has_access on profiles.

Do not rebuild Checkout. Set the price ID and the webhook secret.

Keys

In the Stripe Dashboard:

CredentialEnv varWhere to get it
Secret keySTRIPE_SECRET_KEYDevelopers → API keys
Webhook signing secretSTRIPE_WEBHOOK_SECRETDevelopers → Webhooks → your endpoint
Price IDNEXT_PUBLIC_STRIPE_PRICE_IDProduct catalog → the price (price_...)

STRIPE_PUBLIC_KEY is in .env.example and unused. Skip it.

Create the product

  1. Product catalog → Add product
  2. One-time price for a lifetime licence, or recurring for a subscription
  3. Copy the Price ID into NEXT_PUBLIC_STRIPE_PRICE_ID
  4. Match stripe.plans[0].price in config.ts to what Stripe charges so the card is honest

ButtonCheckout defaults to mode="payment". For a subscription price, pass mode="subscription" on the button. The webhook already handles both.

Webhook

Point Stripe at:

text
https://your-domain.com/api/webhook/stripe

Use the Stripe CLI:

bash
stripe listen --forward-to localhost:3000/api/webhook/stripe

Paste the whsec_... value it prints into STRIPE_WEBHOOK_SECRET.

Select these events. The route already handles them:

EventWhat happens
checkout.session.completedMatch the plan, find or create the user, set access, send the welcome email
customer.subscription.deletedSet has_access to false
invoice.paidRe-grant access when the invoice price matches price_id
checkout.session.expiredNo-op
customer.subscription.updatedNo-op
invoice.payment_failedNo-op. Stripe retries, then sends customer.subscription.deleted

Signature verification is required. Do not skip it.

Customer portal

Turn on Settings → Billing → Customer portal. ButtonAccount on the dashboard opens it after the customer has a customer_id. Receipts and cancellations stay in Stripe.

Test it

  1. profiles table exists (Supabase)
  2. Webhook is forwarding
  3. Use 4242 4242 4242 4242 in test mode
  4. Confirm has_access is true on the profile

Then gate the dashboard. The flag is written. Your product still has to read it.