DEV Community

楊東霖
楊東霖

Posted on • Originally published at devplaybook.cc

Webhook Testing: How to Debug, Inspect, and Replay Webhooks in 2026

Webhook Testing: How to Debug, Inspect, and Replay Webhooks in 2026

What is a Webhook?

A webhook is an HTTP POST request sent from one service to another when an event happens. Your server receives it and reacts.

Stripe event happens (payment.success)
  → POST https://yoursite.com/api/webhook/stripe
  → Your server processes it
Enter fullscreen mode Exit fullscreen mode

Testing Webhooks Locally

Step 1: Expose Localhost

# ngrok (free tier)
ngrok http 3000

# cloudflared (Cloudflare, free)
cloudflared tunnel --url http://localhost:3000

# Both give you a public URL like:
# https://abc123.ngrok.io
Enter fullscreen mode Exit fullscreen mode

Step 2: Register the Webhook

In your service dashboard (Stripe, GitHub, Slack):

Payload URL: https://abc123.ngrok.io/api/webhook/handler
Events: payment_intent.succeeded, payment_intent.failed
Enter fullscreen mode Exit fullscreen mode

Verifying Webhook Signatures

Always verify signatures. Never trust the payload blindly.

// Express.js webhook handler with Stripe signature verification
const express = require('express');
const crypto = require('crypto');

const app = express();

app.post('/api/webhook/stripe', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['stripe-signature'];
  const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;

  try {
    const event = crypto.timingSafeEqual(
      Buffer.from(sig),
      Buffer.from(webhookSecret)
    );
    // ✅ Verified
    const payload = JSON.parse(req.body);
    handleEvent(payload);
    res.json({ received: true });
  } catch (err) {
    res.status(400).send(`Webhook Error: ${err.message}`);
  }
});
Enter fullscreen mode Exit fullscreen mode

Replaying Webhooks

# With Stripe CLI
stripe trigger payment_intent.succeeded

# Or replay a specific event
stripe events resend evt_1234567890
Enter fullscreen mode Exit fullscreen mode

Common Webhook Mistakes

Mistake Fix
Responding with non-2xx Always return 200 quickly, process async
Not handling duplicates Use idempotency keys
Forgetting to verify signatures Always verify, always
Long-running processing Queue the event, respond immediately

Retry Logic

Services like Stripe retry failed webhooks:

Attempt 1: Immediate
Attempt 2: 5 minutes later
Attempt 3: 30 minutes later
Attempt 4: 1 hour later
Attempt 5: 2 hours later
Total: ~3.5 hours before giving up
Enter fullscreen mode Exit fullscreen mode

Your handler should:

  1. Return 200 immediately
  2. Queue the event for processing
  3. Process in background

Testing Tools

Tool Use Case
ngrok Local tunneling
RequestBin Capture and replay
Webhook.site Free webhook testing
Stripe CLI Stripe-specific testing
GitHub CLI GitHub webhook testing

Level Up Your Dev Workflow

Found this useful? Explore DevPlaybook — cheat sheets, tool comparisons, and hands-on guides for modern developers.

🛒 Get the DevToolkit Starter Kit on Gumroad — 40+ browser-based dev tools, source code + deployment guide included.

Top comments (0)