Next.js cookbook · Intermediate
Receive Stripe webhooks in a Next.js Route Handler
Process payment events securely in a Next.js app deployed to serverless.
Approach
In a Route Handler, read the raw body with await request.text(), verify with the provider SDK (stripe.webhooks.constructEvent) using the signing secret, deduplicate by event ID, do minimal work and return 200. Run on the Node.js runtime when the SDK needs Node APIs.
Solution
// app/api/webhooks/stripe/route.ts
import Stripe from "stripe";
import { stripe } from "@/lib/stripe";
export const runtime = "nodejs";
export async function POST(request: Request) {
const body = await request.text();
const signature = request.headers.get("stripe-signature");
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(body, signature!, process.env.STRIPE_WEBHOOK_SECRET!);
} catch {
return new Response("Invalid signature", { status: 400 });
}
const inserted = await db.webhookEvent.createMany({ data: [{ id: event.id, type: event.type }], skipDuplicates: true });
if (inserted.count === 0) return new Response("Duplicate", { status: 200 });
switch (event.type) {
case "checkout.session.completed":
await orders.markPaid((event.data.object as Stripe.Checkout.Session).metadata!.orderId);
break;
case "customer.subscription.deleted":
await subscriptions.cancel((event.data.object as Stripe.Subscription).id);
break;
}
return Response.json({ received: true });
}
Pitfalls
- Parsing JSON before verification (
request.json()loses the raw body). - Long processing inside the handler (timeouts → retries).
- Assuming events arrive in order.
Variations
- Queue heavy work (Inngest, QStash, a worker) and return immediately.
Further reading: Stripe: Webhooks quickstart
Reference: https://docs.stripe.com/webhooks/quickstart?lang=node
More Next.js recipes
- Add a Content Security Policy with nonces in Next.js
- Add dark mode to Next.js without a flash
- Add SEO metadata, Open Graph and sitemaps
- Avoid data-fetching waterfalls in Server Components
- Build a validated JSON API with Route Handlers
- Create encrypted session cookies in Next.js
- Handle errors and 404s in the App Router
- Handle forms with Server Actions and validation