Immutable solution version
Stripe webhooks on Next.js Pages Router: disable bodyParser, verify from the buffer
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: falseis 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>