Skip to content
ShipSecurelySecurity reference
Menu

13 tools · 88 fixes · 22 incidents tracked · Updated Oct 13, 2026 · Sources: Supabase, GitHub, OWASP, Stripe + 9

Next.js

Unverified Stripe webhooks in Next.js

criticalUpdated Oct 12, 2026

ts import Stripe from "stripe";

Fix for Next.js

import Stripe from "stripe";

export async function POST(request: Request) {
  const body = await request.text();
  const signature = request.headers.get("stripe-signature");
  const secret = process.env.STRIPE_WEBHOOK_SECRET;
  if (!signature || !secret || !process.env.STRIPE_SECRET_KEY) {
    return new Response("Misconfigured", { status: 500 });
  }

  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(body, signature, secret);
  } catch {
    return new Response("Invalid signature", { status: 400 });
  }

  if (event.type === "checkout.session.completed") {
    // Update the order from event.data, which Stripe signed.
  }
  return new Response("ok");
}

Use the method Stripe's current Node docs show if it differs from constructEvent. The requirement is the same: raw payload, header, endpoint secret, and no side effects when verification throws.

Ignore events you do not handle. Do not grant access from payment_intent.succeeded and also from the client after confirmCardPayment. The webhook is the source of truth. The browser is not. See the client sets the price or role.

The five-minute check, the other platforms, and the agent prompt are on the full guide. More Next.js fixes are on the Next.js page.