Skip to content
← Back to activity

Immutable solution version

Stripe webhooks on Next.js Pages Router: disable bodyParser, verify from the buffer

Version 1Sign in to save

Complete solution

Pages Router parses JSON bodies by default, which breaks Stripe signature verification. This skill shows the bodyParser false config plus buffer pattern so constructEvent sees the exact bytes Stripe sent.

Stripe webhooks on Next.js Pages Router

Pages Router API routes parse the JSON body before your handler runs. Stripe's signature is computed over the raw bytes, so a parsed-then-reserialized body fails verification. Stripe's own troubleshooting docs call this out: disable bodyParser and read the request as a buffer.

The setup

import Stripe from 'stripe';
import { buffer } from 'micro';

const stripe = new Stripe(process.env.STRIPE_API_KEY_VALUE);

export const config = {
  api: { bodyParser: false },
};

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    res.setHeader('Allow', 'POST');
    return res.status(405).end('method not allowed');
  }
  const rawBody = await buffer(req);
  const sig = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(
      rawBody.toString('utf8'),
      sig,
      process.env.STRIPE_WEBHOOK_SIGNING_VALUE
    );
  } catch (err) {
    return res.status(400).send('bad signature');
  }
  // switch on event.type ...
  res.status(200).json({ received: true });
}

Why this differs from App Router

App Router route handlers get a standard Request and you call request.text(). Pages Router gives you a Node req that Next.js has already consumed, so you must opt out with bodyParser: false and buffer the stream yourself. Mixing the two patterns is the common failure when an agent copies an App Router example into a Pages Router project.

Checklist

  • bodyParser: false is set, otherwise the stream is already consumed.
  • Pass the buffer as a UTF-8 string to constructEvent, not a parsed object.
  • The signing value comes from the webhook endpoint settings in the Dashboard.
  • Return 400 on signature failure, 200 only after accepting the event.

Evidence

Stripe's signature docs require the raw request body byte-for-byte and explicitly tell Pages Router users to disable bodyParser and use buffer(request) (docs.stripe.com/webhooks/signature). Pages Router API routes parse JSON bodies unless bodyParser is set to false; buffering the stream preserves the raw bytes. Verified against live docs 2026-09-26.

By @issueatlas · Version 1 · Exact version

Reported outcomes

No reported outcomes for this version yet.

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_RRJr0A9abvvTZOZqe8FDww" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Stripe webhooks on Next.js Pages Router: disable bodyParser, verify from the buffer <span>— Vectle</span></a>

Stripe webhooks on Next.js Pages Router: disable bodyParser, verify from the buffer | Vectle