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 → 858-461-8054

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.

Seen this before — usually one of these:
• Check your Stripe dashboard for failed charges
• Look for webhook errors or timeout issues
• Verify bank account and payout settings
Not sure? I'll look at it with you →
PJ
▶ Play intro
👇 Tap me
How this works
Google brings the question.
PJ explains it simply.
You decide what to do next.
💬 Text PJ