Stripe webhooks not working?
You're not alone — it's one of the most common issues when integrating Stripe in a SaaS.
The tricky part is that sometimes… they actually are working.
- events are received
- 200 responses are returned
- logs look fine
But your system still breaks.
That’s because most webhook issues are not about Stripe — they’re about backend logic.
Why Stripe webhooks “don’t work”
The most common causes:
- body parsing modifies the request
- wrong webhook secret (test vs live)
- endpoint is unreachable
- returning 200 without real processing
The worst case is this:
Your server returns 200 OK, but doesn't actually update anything.
Stripe stops retrying, and your system slowly goes out of sync.
Common mistakes
- using
express.json()instead ofexpress.raw() - not verifying the webhook signature
- not handling duplicate events
- relying on frontend redirects
- not logging events properly
Correct Stripe webhook setup (Node.js)
app.post('/webhook/stripe', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.error('Webhook signature verification failed.', err.message);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Update your database
// Grant access to the user
grantAccessToUser(session.customer_email);
}
res.status(200).send();
});
How to debug Stripe webhooks
When something doesn’t work, follow this:
- Check Stripe Dashboard → Events
- Verify if the event was delivered
- Inspect backend logs
- Replay events from Stripe
- Double-check webhook secret
In most cases, the issue becomes obvious here.
The most dangerous pattern
A very common anti-pattern looks like this:
res.json({ received: true });
…without actually handling the event.
👉 Stripe thinks everything is fine
👉 stops retrying
👉 your system silently breaks
Best practices
- make your system idempotent
- store event IDs
- handle retries correctly
- never trust the frontend
- always verify webhook signatures
Real production issue
This is where things get dangerous:
- payment succeeds
- webhook fires
- backend returns 200
- but logic is incomplete
Everything looks healthy…
Until:
- users lose access
- subscriptions go out of sync
- revenue silently drops
When this becomes a system problem
If you’ve worked with Stripe before, you know this logic grows fast:
- subscriptions
- usage-based billing
- credits (AI, APIs, etc.)
- access control
At some point, it stops being a simple integration problem.
It becomes a system problem.
That’s something I’ve been exploring recently — especially around making Stripe integrations more reliable by design.
More details
I also wrote a deeper breakdown here:
👉 https://www.sos-guide.it/stripe-webhook-non-funziona-guida-per-debug-e-fix/
Final takeaway
Stripe webhooks don’t “fail” randomly.
They fail when:
- your backend logic is incomplete
- events are not handled correctly
- systems are not designed for async flows
If you treat Stripe as the source of truth and design your backend around it, most of these issues disappear.
What’s the most confusing webhook issue you’ve ever debugged?
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.