How to Debug Stripe Webhooks in 2026
Master Stripe webhook debugging with practical techniques. Learn to trace failures, inspect payloads, handle retries, and use HookSense for real-time webhook inspection.
Ozer
Developer & Founder of HookSense
Stripe webhooks are the nervous system of any payment integration. They tell your application when a charge succeeds, a subscription renews, a dispute is filed, or a payout lands. But when something goes wrong — and it will — debugging webhooks can feel like chasing ghosts. The request arrived, something failed, and you have no idea what the payload looked like or why your handler choked.
This guide covers practical, battle-tested techniques for debugging Stripe webhooks in 2026. Whether you are building your first checkout flow or maintaining a mature billing system, these strategies will save you hours of frustration.
Understanding the Stripe Webhook Lifecycle
Before diving into debugging, it helps to understand exactly what happens when Stripe sends a webhook:
- An event occurs in your Stripe account (e.g., a payment succeeds).
- Stripe creates an Event object with a unique ID, type, and nested
data.objectcontaining the relevant resource. - Stripe sends an HTTP POST to each registered endpoint URL with the Event as JSON in the body.
- Your server has 20 seconds to respond with a 2xx status code. If it does not, Stripe marks the delivery as failed.
- Stripe retries failed deliveries with exponential backoff — up to 3 days for live mode and 3 hours for test mode.
Most debugging problems fall into one of four categories: the webhook never arrives, the signature verification fails, the handler throws an error, or the response times out.
Problem 1: Webhooks Not Arriving
If your endpoint is not receiving any events at all, check these items first:
- Endpoint URL: Open the Stripe Dashboard, navigate to Developers → Webhooks, and verify the URL is correct. A trailing slash mismatch (
/webhooksvs/webhooks/) can cause a 404. - Event selection: Make sure you have subscribed to the specific events you expect. If you only selected
checkout.session.completed, you will not receivepayment_intent.succeeded. - Endpoint status: Stripe disables endpoints that fail consistently. Check if your endpoint shows a red "Disabled" badge in the dashboard.
- Firewall rules: If your server sits behind a WAF or CDN, Stripe's IP ranges might be blocked. Stripe publishes their webhook IP ranges in their documentation.
Problem 2: Signature Verification Failures
Stripe signs every webhook with a secret unique to each endpoint. The most common signature verification mistakes are:
// WRONG: Using parsed JSON body
app.post('/webhooks', express.json(), (req, res) => {
// req.body is already parsed — signature check will FAIL
stripe.webhooks.constructEvent(JSON.stringify(req.body), sig, secret);
});
// CORRECT: Using raw body
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
// req.body is a Buffer — signature check will pass
stripe.webhooks.constructEvent(req.body, sig, secret);
});
Key takeaway: The signature is computed against the exact bytes Stripe sent. If your framework parses the body before your verification code runs, the bytes change, and the signature no longer matches. Always verify against the raw body.
Other common causes include using the wrong endpoint secret (each endpoint has its own whsec_... key) and clock skew beyond the 5-minute tolerance window.
Problem 3: Handler Errors
Your endpoint receives the webhook, verifies the signature, but then your business logic throws an error. These are the hardest bugs to catch because Stripe considers the delivery successful as long as you return a 2xx — even if your handler crashes afterwards in an async process.
Best practices for handler debugging:
- Return 200 immediately, then process: Acknowledge receipt before running business logic. This prevents timeouts and gives you time to process.
- Log the full event: Store the raw JSON payload in your database or logging system before processing. If something fails later, you have the original data.
- Use idempotency keys: Stripe may send the same event multiple times during retries. Use the event ID (
evt_...) to deduplicate and avoid processing the same charge twice. - Handle event types explicitly: Use a switch statement and log unhandled types. A catch-all that silently ignores unknown events will hide bugs.
Problem 4: Timeouts
If your handler takes more than 20 seconds, Stripe considers the delivery failed and schedules a retry. This commonly happens when your handler makes slow external API calls, runs heavy database queries, or sends emails synchronously.
The fix: acknowledge the webhook immediately and move heavy processing to a background job queue (Bull, SQS, Celery, etc.).
Using the Stripe Dashboard for Debugging
The Stripe Dashboard provides built-in webhook debugging under Developers → Webhooks → [Your Endpoint]:
- Event deliveries: Shows every attempt with status code, response body, and timing.
- Resend: You can manually resend any event from the dashboard — useful for retesting after a fix.
- Event data: Click any event to see the full JSON payload.
This is useful but limited. You cannot search across events, compare payloads side by side, or forward events to your local machine.
Debugging with HookSense
HookSense fills the gaps that the Stripe Dashboard leaves open. Here is a workflow that has saved us countless hours:
Step 1: Create a HookSense Endpoint
Sign up at hooksense.com and create a new endpoint. Copy the URL (e.g., https://hooksense.com/w/abc123).
Step 2: Add It as a Stripe Webhook
In your Stripe Dashboard, add the HookSense URL as a new webhook endpoint. Select the events you want to debug. You can keep your production endpoint active — Stripe sends events to all registered endpoints.
Step 3: Inspect in Real Time
Open HookSense in your browser. Every webhook from Stripe appears instantly via WebSocket — no refreshing required. You see headers, the full JSON body with syntax highlighting, and the response status.
Step 4: Forward to Localhost
Run the HookSense CLI to forward every captured webhook to your local development server:
npx hooksense listen -p 3000
Now you can set breakpoints in your IDE, step through your handler code, and see exactly where things go wrong — all with real Stripe payloads.
Step 5: Replay After Fixes
Found and fixed the bug? Click the replay button on any captured webhook to send it again. No need to trigger a new Stripe event or ask a colleague to make a test purchase.
Stripe Webhook Debugging Checklist
| Check | What to verify |
|---|---|
| Endpoint URL | Correct URL, no trailing slash mismatch |
| Event selection | Subscribed to the right event types |
| Raw body | Signature verification uses raw bytes, not parsed JSON |
| Endpoint secret | Using the correct whsec_... for this specific endpoint |
| Response time | Handler responds within 20 seconds |
| Idempotency | Deduplicating by event ID to handle retries safely |
| Error handling | Catching exceptions and logging before returning 200 |
| Endpoint status | Not disabled in Stripe Dashboard due to repeated failures |
Conclusion
Webhook debugging does not have to be painful. Most issues come down to a handful of common mistakes: wrong URL, parsed body, missing event types, or slow handlers. With structured logging, a solid checklist, and a tool like HookSense that gives you real-time inspection and replay, you can diagnose and fix webhook issues in minutes instead of hours.
Related
Try HookSense Free
Inspect, debug, and replay webhooks in real-time. No credit card required.
Get Started Free