Boilerplate-Stack
Back to blog
Articles

How to Set Up Stripe Webhooks in Next.js App Router

|
2 min read

Setting up Stripe correctly in a Next.js SaaS rarely takes less than 5 hours. Between signature verification, idempotent event handling, price-to-plan mapping, and atomic subscription updates in the database, every step hides a trap. Here is the complete method to do it cleanly with the App Router.

1. Create the webhook route

In app/api/stripe/webhook/route.ts, export a POST handler. The signature must be verified BEFORE parsing the body. Next.js 16 exposes request.text() to grab the raw body needed for verification.

const sig = request.headers.get('stripe-signature')!
const body = await request.text()
const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!)

2. Handle the key events

At minimum, four events must be handled:

  • checkout.session.completed — subscription creation or one-time purchase
  • customer.subscription.updated — sync plan changes
  • customer.subscription.deleted — mark subscription as canceled
  • invoice.paid — monthly credit refill

3. Map Stripe Price IDs to plans

Store plans in code (not the database). The webhook matches line_items[0].price.id to your configuration. This avoids migrations every time you tweak pricing.

4. Idempotency and atomicity

Stripe can re-emit an event. Persist the event.id and skip duplicates. For credits, use SQL RPCs (decrement_credits, add_credits) — never a direct UPDATE.

5. Test locally

Use the Stripe CLI: stripe listen --forward-to localhost:3000/api/stripe/webhook then stripe trigger customer.subscription.created to simulate each event.

Don't waste 5 hours wiring Stripe. The complete, idempotent, production-ready code is included in Boilerplate-Stack — webhooks, credit packs, customer portal, and subscriptions.

Conclusion

Stripe webhooks are the pillar of modern billing but full of pitfalls. Once wired correctly, they become invisible. Boilerplate-Stack implements this entire flow and much more in a production-ready starter kit.