Payment Webhooks
LaunchKit Pro ingests billing webhooks from Stripe and Lemon Squeezy when BILLING_PROVIDER is set to the matching provider. Mock billing uses POST /billing/webhooks/mock for development only.
HTTPS required in production
Provider dashboards must call your public API URL over HTTPS. Local testing typically uses Stripe CLI or Lemon Squeezy forwarding tools.
Endpoints
| Provider | Method | Path |
|---|---|---|
| Stripe | POST | /billing/webhooks/stripe |
| Lemon Squeezy | POST | /billing/webhooks/lemon-squeezy |
| Mock (dev) | POST | /billing/webhooks/mock |
Full URLs (production example):
https://api.yourdomain.com/billing/webhooks/stripe
https://api.yourdomain.com/billing/webhooks/lemon-squeezyStripe
Env: STRIPE_WEBHOOK_SECRET (signing secret from Stripe Dashboard or CLI)
Verification: Raw request body + Stripe-Signature header
Handled events (foundation):
checkout.session.completedinvoice.payment_succeededinvoice.payment_failedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deleted
Stored provider IDs: stripeCustomerId, stripeSubscriptionId, stripeCheckoutSessionId, stripeInvoiceId
Metadata synced: userId, workspaceId, editionKey, app=launchkit-pro
Invalid signatures are rejected. Duplicate events are ignored via unique provider event IDs.
Local testing (Stripe CLI)
stripe listen --forward-to localhost:4000/billing/webhooks/stripe
# Copy whsec_... into STRIPE_WEBHOOK_SECRET for local devLemon Squeezy
Env: LEMON_SQUEEZY_WEBHOOK_SECRET
Verification: Raw request body + X-Signature header; event name from X-Event-Name
Handled events (foundation):
order_createdsubscription_createdsubscription_updatedsubscription_cancelledsubscription_expiredsubscription_payment_successsubscription_payment_failed
Stored provider IDs: lemonCustomerId, lemonOrderId, lemonSubscriptionId, lemonVariantId, lemonProductId
Custom data synced: userId, workspaceId, editionKey, app=launchkit-pro
Receipt or order URLs are stored when the provider payload includes them.
Idempotency and sync
- Webhook events are recorded in
BillingWebhookEventwith unique(provider, providerEventId)constraints - Payment rows use unique
(provider, providerPaymentId)where applicable - Subscription status, period dates, and workspace current edition update from webhook payloads
- API returns 2xx only after safe processing
After redirect checkout, the dashboard may show "Payment status will update after webhook confirmation." until the provider webhook arrives.
Developer webhooks (separate)
Workspace Developer Tools webhooks are outbound webhooks sent from LaunchKit Pro to customer endpoints. They are unrelated to payment provider webhooks.
Developer webhooks send signed JSON POST requests for these event types:
workspace.createdworkspace.updateduser.createdbilling.checkout_completedbilling.subscription_updatedlicense.activatedai.generation_createdfile.uploaded
Each request includes X-LaunchKit-Event, X-LaunchKit-Delivery, X-LaunchKit-Timestamp, and X-LaunchKit-Signature. The signature is HMAC-SHA256(timestamp + "." + rawJsonPayload) using the endpoint secret shown once when the webhook is created.
Delivery can be disabled with WEBHOOK_DELIVERY_ENABLED=false. Demo delivery is blocked by default with WEBHOOK_DEMO_DELIVERY_DISABLED=true. See Developer Tools for API key usage, outbound webhook delivery logs, retries, and signature verification examples.