Stripe: webhook signature verification failing [2026 fix]

Webhook signature verification fails when endpoint_secret is missing or mismatched. Copy the correct signing secret from Dashboard and pass it to verifyHeader().

Stripe: webhook signature verification failing [2026 fix]

TL;DR

Cause: Your webhook endpoint is using the wrong or missing endpoint_secret (signing secret from Stripe Dashboard). Fix: Copy the correct signing secret from Stripe Dashboard → Developers → Webhooks → select endpoint → "Signing secret" and pass it to stripe.webhooks.constructEvent().

---

Real Console Error Messages

These are the exact errors you'll see at 2am:

``` Error: No signatures found matching the expected signature for payload. computed signature=<hash>, attempted signature versions=[v1] ```

``` StripeSignatureVerificationError: No signatures found matching the expected signature for payload at Function.constructEvent (/node_modules/stripe/lib/webhooks.js:104:15) ```

``` Webhook Error: error decoding event request body: json: cannot unmarshal string into Go struct field Event.created of type int64 ```

``` stripe.error.SignatureVerificationError: No signatures found matching the expected signature for payload ```

``` Fatal error: HMAC verification failed. Expected signature header 'stripe-signature' not found. ```

---

Broken Code vs. Exact Fix

❌ BROKEN (Most Common)

```javascript // webhook.js - WRONG const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => { // ❌ Missing endpoint_secret parameter const event = stripe.webhooks.constructEvent( req.body, req.headers['stripe-signature'], // MISSING: endpoint_secret here! ); res.json({received: true}); }); ```

✅ FIXED

```javascript // webhook.js - CORRECT const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => { // ✅ Pass the signing secret from Stripe Dashboard const event = stripe.webhooks.constructEvent( req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET // ← Copy from Dashboard ); res.json({received: true}); }); ```

❌ BROKEN (Wrong Secret Used)

```javascript // ❌ Using publishable key instead of webhook signing secret const event = stripe.webhooks.constructEvent( req.body, req.headers['stripe-signature'], process.env.STRIPE_PUBLISHABLE_KEY // WRONG! This is not a signing secret ); ```

✅ FIXED

```javascript // ✅ Use ONLY the webhook endpoint's signing secret const event = stripe.webhooks.constructEvent( req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET // From: Dashboard → Webhooks → select endpoint → "Signing secret" ); ```

❌ BROKEN (String Body Instead of Raw)

```javascript // ❌ Using express.json() instead of express.raw() app.post('/webhook', express.json(), (req, res) => { // This converts body to string, breaking HMAC verification const event = stripe.webhooks.constructEvent( req.body, // ❌ Already parsed, signature fails req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET ); }); ```

✅ FIXED

```javascript // ✅ MUST use express.raw() to preserve raw bytes for HMAC app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => { const event = stripe.webhooks.constructEvent( req.body, // ✅ Still raw buffer, HMAC verifies req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET ); }); ```

---

How to Find Your Signing Secret

1. Go to [Stripe Dashboard](https://dashboard.stripe.com) 2. Navigate: DevelopersWebhooks 3. Find your endpoint URL in the list 4. Click on it 5. Scroll to Signing secret section 6. Click Reveal 7. Copy the secret starting with whsec_ 8. Add to .env: ``` STRIPE_WEBHOOK_SECRET=whsec_test_xxxxxxxxxxxx ``` 9. Restart your server 10. Test with stripe trigger payment_intent.succeeded --skip-confirmation

---

Version-Specific Notes

Stripe Node.js SDK (v8.0.0+): The constructEvent() method signature is consistent. However, we cannot guarantee behavior in versions prior to v7.0.0—if you're on an older version, upgrade with npm install stripe@latest.

Express.js: The express.raw() middleware requirement applies to Express 4.16.0+. Older versions may need body-parser middleware instead.

---

Still broken? Check these too

1. Webhook endpoint is offline: Stripe retries for 3 days. Check server logs. If your endpoint crashed, [related guide: debugging Express 500 errors](/?guide=express-errors).

2. Multiple webhook endpoints configured: You have one signing secret *per endpoint*. Verify you're using the secret matching your exact URL, not another endpoint's secret.

3. Body middleware conflict: Ensure no global express.json() middleware processes the webhook route *before* express.raw(). Move webhook route to top of middleware stack or use route-specific middleware: [related: middleware ordering](/?guide=middleware-order).

4. Stripe CLI testing without secret: If testing locally with stripe listen, the CLI auto-generates a signing secret. When you run stripe listen --forward-to localhost:3000/webhook, it prints the secret—use that exact value.

5. Environment variable not loaded: Confirm process.env.STRIPE_WEBHOOK_SECRET is populated by logging it (never log in production). Check .env file format: no quotes, no spaces.

---

Official Documentation

[Stripe Webhook Signing (Official Docs)](https://stripe.com/docs/webhooks/signatures)

---

Found a different variation? Drop it in the comments below—we'll add it to this guide.

🔥 0d
LIVE
PlanetScale rage spiking Vercel pricing complaints Railway gaining fast Supabase happiness rising Resend loved by devs PlanetScale rage spiking Vercel pricing complaints Railway gaining fast Supabase happiness rising
DEVELOPER PAIN RADAR // Loading...

Developers complain.
Opportunities appear.

We track what developers are struggling with today — and what opportunities that creates.

guides today
avg happiness
🔥 Pain
📖 Guides
🔭 Explore
👤 Mine
🔥 Pain Radar — rage scores today
↗ share
💡 Opportunity Feed — pain = market gap
📈 Tool Momentum
all scores →
📖 Latest Guide
all guides →
📖 All Guides
📊 Tool Scores
+ Submit
📰 Hacker News
➕ Submit a Tool
← back