Billing
Webhooks
How payment webhooks are processed for Stripe and Lemon Squeezy.
Stripe webhooks
Route: POST /api/stripe/webhook
| Event | Action |
|---|---|
checkout.session.completed | Records order, delivers access |
customer.subscription.created | Creates subscription record |
customer.subscription.updated | Updates subscription (plan, status, period) |
customer.subscription.deleted | Sets status to canceled |
invoice.payment_succeeded | Records order for revenue tracking |
invoice.payment_failed | Sets status to past_due |
Lemon Squeezy webhooks
Route: POST /api/lemonsqueezy/webhook
| Event | Action |
|---|---|
order_created | Records order for revenue tracking |
order_refunded | Marks order as refunded |
subscription_created | Creates subscription record |
subscription_updated | Updates subscription status and period |
subscription_cancelled | Sets status to canceled |
subscription_payment_success | Records order for revenue |
subscription_payment_failed | Sets status to past_due |
Testing webhooks locally
Stripe
stripe listen --forward-to localhost:3000/api/stripe/webhookLemon Squeezy
Use a tunneling service like ngrok or Cloudflare Tunnel to expose your local server, then set the webhook URL in the Lemon Squeezy dashboard.