Stripe: Webhook payload must be provided as a string or a Buffer (raw body)
stripe-node throws this when constructEvent() receives a parsed JavaScript object instead of the raw request body. Give the webhook route the unparsed body (a string or Buffer) before any JSON middleware touches it.
Cause: A JSON body parser (e.g. express.json() or req.json()) ran before signature verification.
How to fix it
- Mount the webhook route with a raw body parser (
express.raw({ type: 'application/json' })) before globalexpress.json(). - In Next.js route handlers use
await req.text(), notreq.json(). - Pass that raw body, the
Stripe-Signatureheader and your endpoint secret toconstructEvent(). - Parse the JSON only after verification succeeds.
Example
Illustrative example, not from a customer project.
- const body = await req.json()
+ const body = await req.text()
const event = stripe.webhooks.constructEvent(body, sig, secret)
FAQ
Is this the same as 'No signatures found matching the expected signature'?
Related. This one fires when the body is an object; the other when the body, header or secret doesn't match.
Why can't Stripe verify parsed JSON?
The signature is computed over the exact bytes Stripe sent; re-serialized JSON can differ.
Get a $149 diagnosis See pricing Stripe still not live? We take it live at a fixed price.
- Fixed, or we keep working free until it is (within the written scope).
- A human reviews every fix before it ships.
- read-only access; fixes arrive as pull requests you merge
- Your $149 diagnosis is credited in full toward any paid job.