Stripe · Problem Fix

Stripe Signature Verification Failed

Your webhook endpoint is receiving Stripe events but signature verification throws an error. This is almost always a raw body parsing issue — your framework is parsing the JSON before Stripe can verify the original signature.

1. Body parsed before stripe.webhooks.constructEvent()

Stripe's signature is computed against the raw bytes of the request body. If your framework (Express, Next.js, etc.) parses the JSON body first (converting it to a JavaScript object), the raw bytes are gone. You must pass the raw buffer, not the parsed object. In Express: use express.raw({type: 'application/json'}) for the webhook route. In Next.js App Router: read req.text() not req.json().

2. Wrong webhook secret (endpoint secret vs API key)

stripe.webhooks.constructEvent() takes your webhook signing secret — not your Stripe API key. The signing secret starts with 'whsec_' and is found in Dashboard > Developers > Webhooks > your endpoint > Signing secret. Using your API key (sk_live_ or sk_test_) here will always fail.

3. Using test webhook secret with live events

Stripe has separate signing secrets for test mode and live mode webhooks. If you're testing with test events, use the test endpoint's whsec_. If receiving live events, use the live endpoint's whsec_. Cross-mode secrets always fail verification.

4. Timestamp tolerance exceeded

Stripe includes a timestamp in the webhook payload and rejects verification if the timestamp is more than 5 minutes old (configurable). If your server clock is off or you're replaying old events for testing, verification fails. Use stripe.webhooks.constructEvent(payload, header, secret, {tolerance: 300}) or increase tolerance for testing.

5. Middleware modifying the request body before your handler

Body-parsing middleware (body-parser, next.js default JSON parser) applied globally will consume the raw body before your webhook handler sees it. Ensure your webhook route explicitly bypasses the global JSON parser and reads the raw body directly.

Still stuck? Text PJ.

Real operator. No ticket queue. San Diego-based. Most issues resolved in one thread.

Text PJ → 773-544-1231

Related problems in this cluster:

Stripe webhook not working Vercel env var not loading Webhook works local not prod
💬 Text PJ

Know someone who should see this? Share the idea and the feeling in one tap.