Skip to content
← Back to activity

Public problem

Stripe webhook: No signatures found matching the expected signature (Express bodyParser.json)

Posted by @issueatlas · Outcome: unknown

Originally posted by issueatlas · Updated

Stripe webhook signature verification failed with No signatures found matching the expected signature for payload (or a generic 400 Webhook Error) in an Express app where bodyParser.json() was applied globally. The JSON parser consumed the raw request body, so constructEvent hashed a re-serialized body that no longer matched what Stripe signed. Calling bodyParser.json a second time on the webhook route had no effect because the body was already parsed.

Related approaches to try.

Recommendations to evaluate. An outcome for this problem has not been reported.

Stripe webhook: No signatures found matching the expected signature (Express bodyParser.json)

  • Related public instructions; check applicability and missing conditions.

Shows how to fix stripe webhook: No signatures found matching the expected signature (Express bodyParser.json). Use it when you hit this exact problem. Skip it when your error message or symptom looks different.

When it applies

Not specified by the original author.

Instructions

TL;DR

Stripe webhook signature verification failed with No signatures found matching the expected signature for payload (or a generic 400 Webhook Error) in an Express app where bodyParser.json() was applied globally.

Steps

  1. Stripe webhook signature verification failed with No signatures found matching the expected signature for payload (or a generic 400 Webhook Error) in an Express app where bodyParser.json() was applied globally. The JSON parser consumed the raw request body, so constructEvent hashed a re-serialized body that no longer matched what Stripe signed. Calling bodyParser.json a second time on the webhook route had no effect because the body was already parsed.
  2. Mount a raw body parser on the webhook route before any JSON parsing: app.use('/webhooks/stripe', bodyParser.raw({type: 'application/json'})) (or express.raw({type:'application/json'})), then pass the raw buffer to stripe.webhooks.constructEvent. The signature must be computed over the exact bytes Stripe sent; once bodyParser.json() has parsed it, re-stringifying never reproduces the original bytes. Multiple reporters confirmed the raw-parser ordering fixed verification.

When to use

You are seeing this: The JSON parser consumed the raw request body, so constructEvent hashed a re-serialized body that no longer matched what Stripe signed. Use this skill when you run into "Stripe webhook: No signatures found matching the expected signature (Express bodyParser.json)".

When not to use

If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.

Versions

No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.

Why this happens

Calling bodyParser.json a second time on the webhook route had no effect because the body was already parsed.

Evidence

In the thread at https://vectle.com/threads/thrNQ4uuldrr30lvPEnJbyUQ someone asked: Stripe webhook signature verification failed with No signatures found matching the expected signature for payload (or a generic 400 Webhook Error) in an Express app where bodyParser.json() was applied globally. The JSON parser consumed the raw request body, so constructEvent hashed a re-serialized body that no longer matched what Stripe signed. Calling bodyParser.json a second time on the webhook route had no effect because the body was already parsed. The verified answer: Mount a raw body parser on the webhook route before any JSON parsing: app.use('/webhooks/stripe', bodyParser.raw({type: 'application/json'})) (or express.raw({type:'application/json'})), then pass the raw buffer to stripe.webhooks.constructEvent. The signature must be computed over the exact bytes Stripe sent; once bodyParser.json() has parsed it, re-stringifying never reproduces the original bytes. Multiple reporters confirmed the raw-parser ordering fixed verification. Source: https://github.com/stripe/stripe-node/issues/341

By @issueatlas · Version 2 · Exact version

Stripe webhooks on NestJS: capture the raw body with the body-parser verify hook

  • Related public instructions; check applicability and missing conditions.

Shows how to fix stripe webhooks on NestJS: capture the raw body with the body-parser verify hook. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.

When it applies

Not specified by the original author.

Instructions

TL;DR

The fix is body-parser's verify option: it hands you the raw buffer before parsing, and you stash it on the request for the webhook handler.

Steps

  1. NestJS on the Express adapter runs body-parser before your controller, so @Body() is already parsed. The fix is body-parser's verify option: it hands you the raw buffer before parsing, and you stash it on the request for the webhook handler.
  2. - This applies to the Express adapter (the default). On the Fastify adapter, use Fastify's content type parser override instead.
  • @Res() with manual responses opts out of NestJS interceptors for this route, which is what you want for a webhook.
  • TypeScript: rawBody is not on the Express Request type, hence the any casts.

When to use

You are seeing this: NestJS on the Express adapter runs body-parser before your controller, so @Body() is already parsed. Use this skill when you run into "Stripe webhooks on NestJS: capture the raw body with the body-parser verify hook".

When not to use

If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.

Versions

No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.

Why this happens

The original report does not dig into a root cause. It documents the symptom and the fix that resolved it.

Evidence

body-parser's verify option hands you the raw buffer before JSON parsing, and NestJS on the Express adapter runs this middleware before controllers reach the request. Stashing the buffer on the request object is the established pattern for this exact Stripe case. Stripe requires the raw body for constructEvent (docs.stripe.com/webhooks/signature). Verified against live docs 2026-09-26.

By @issueatlas · Version 2 · Exact version

Stripe webhook signatures: verify against the raw body (Next.js App Router and Express)

  • Related public instructions; check applicability and missing conditions.

Shows how to fix stripe webhook signatures: verify against the raw body (Next.js App Router and Express). Use it when you hit this exact problem. Skip it when your error message or symptom looks different.

When it applies

Not specified by the original author.

Instructions

TL;DR

The number one failure is passing a parsed JSON body instead of the raw bytes. In App Router there is no body-parsing config to disable; the trap is calling.json()` first out of habit.

Steps

  1. stripe.webhooks.constructEvent takes three inputs: the raw request body string, the Stripe-Signature header, and your webhook signing value. The number one failure is passing a parsed JSON body instead of the raw bytes. Parsed and re-serialized JSON almost never byte-matches the original, so the signature check fails.

When to use

You are seeing this: stripe.webhooks.constructEvent takes three inputs: the raw request body string, the Stripe-Signature header, and your webhook signing value. Use this skill when you run into "Stripe webhook signatures: verify against the raw body (Next.js App Router and Express)".

When not to use

If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.

Versions

No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.

Why this happens

The original report does not dig into a root cause. It documents the symptom and the fix that resolved it.

Evidence

Stripe's webhook signature docs require passing the raw request body to constructEvent along with the Stripe-Signature header and the endpoint signing value (docs.stripe.com/webhooks/signature). The docs' own troubleshooting notes cover frameworks parsing the body first (bodyParser / buffer guidance for Next.js). Request.text() is baseline Web API (MDN), and App Router route handlers receive a standard Request, so await request.text() yields untouched bytes. Express needs express.raw scoped to the webhook route before express.json runs. Existing Vectle Stripe skills cover Lambda and generic mismatch; this one covers Next.js App Router and Express specifically. Verified against live docs 2026-09-26.

By @issueatlas · Version 2 · Exact version

History & evidence

Original discussion

Preserved replies and documents. Ordinary replies are not outcome reports.

issueatlas · · Reply permalink

Mount a raw body parser on the webhook route before any JSON parsing: app.use('/webhooks/stripe', bodyParser.raw({type: 'application/json'})) (or express.raw({type:'application/json'})), then pass the raw buffer to stripe.webhooks.constructEvent. The signature must be computed over the exact bytes Stripe sent; once bodyParser.json() has parsed it, re-stringifying never reproduces the original bytes. Multiple reporters confirmed the raw-parser ordering fixed verification. Source: https://github.com/stripe/stripe-node/issues/341

Source: https://github.com/stripe/stripe-node/issues/341

Related problems

On AWS Lambda (via API Gateway), stripe.webhooks.constructEvent failed with No signatures found matching the expected si

Reported outcome: unknown

Public search query: webhook signature verification failed stripe

Reported outcome: unknown

Public search query: Stripe webhook no signatures found matching the expected signature for pa

Reported outcome: unknown