Debug your next webhook with Probe.
All articles
#debugging#webhooks#architecture#security·7 min read

How to Debug Failed Webhook Requests: A Production Guide

A step-by-step developer checklist for diagnosing missing, timed-out, rejected, or duplicate webhook deliveries with reproducible test workflows.

Probe

Probe Team

Published September 16, 2026

When an incoming webhook request fails, the fastest path to resolution is capturing the exact byte-for-byte transmission before altering your application code. According to the Postman 2025 State of the API Report, over 41% of webhook integration failures are caused by endpoint misconfigurations, while 31% result from application timeouts during heavy synchronous processing.

Treating the incoming HTTP request as immutable evidence eliminates guesswork. By isolating headers, query parameters, raw body bytes, and delivery timestamps, engineering teams can reproduce production failures locally in minutes.

Common Causes of Webhook Failures

Webhook failures typically fall into four distinct categories: network-level connectivity failures, authentication or signature rejections, downstream application timeouts, and internal handler exceptions.

Root Causes of Webhook Delivery FailuresHorizontal bar chart displaying the distribution of webhook failure causes: Endpoint routing and DNS at 41%, Handler timeouts at 31%, Signature and auth failure at 18%, and Payload schema mismatch at 10%.Route & DNS (41%)41%Timeouts > 5s (31%)31%Signature Failure (18%)18%Schema Drift (10%)10%

Source: Postman State of the API Report & Probe Engineering Telemetry (2025-2026)

Breakdown of primary root causes observed across 250,000+ monitored webhook deliveries.

Step 1: Decode the HTTP Status Code

The HTTP status code recorded in your provider dashboard narrows the search space immediately. Avoid guessing what failed by matching the status code to its underlying protocol constraint.

HTTP StatusPrimary Diagnostic MeaningImmediate Fix
400 Bad RequestThe payload did not conform to your expected schema, or required query params were missing.Check your validation parser against the provider's current API version.
401 / 403 ForbiddenThe webhook signature verification failed or the secret key is invalid.Verify the raw payload buffer; check timestamp tolerance and secret rotation.
404 Not FoundThe destination URL path is wrong, or the deployment route is unmounted.Compare the exact webhook delivery URL with your active routing table.
408 / 504 TimeoutYour handler took longer than the provider timeout window (often 5 to 30 seconds).Acknowledge receipt with 200/202 immediately and move execution to a background queue.
500 Server ErrorAn unhandled exception was thrown inside your business logic handler.Inspect server error traces; wrap handler logic in resilient try/catch blocks.
502 Bad GatewayThe reverse proxy or ingress controller could not reach your backend process.Check container health, port bindings, and upstream application readiness.

Step 2: Check Payload Encoding and Raw Byte Drift

A frequent source of webhook failures is verifying signatures on transformed strings instead of original bytes. Modern web frameworks automatically parse incoming JSON payloads into JavaScript objects. If your signature verification routine serializes the object back into a string, differences in whitespace, key ordering, or Unicode character escaping will invalidate the HMAC hash.

ts
// Correct: Preserve raw request body buffer before parsing
import { createHmac, timingSafeEqual } from 'node:crypto';

export async function handleWebhookRequest(request: Request, secret: string) {
  // 1. Extract raw byte buffer directly from the request stream
  const rawBody = await request.text();
  const signatureHeader = request.headers.get('x-webhook-signature');

  if (!signatureHeader) {
    return new Response('Missing signature header', { status: 401 });
  }

  // 2. Compute expected HMAC SHA-256 hash using the raw string
  const computedHash = createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');

  // 3. Constant-time comparison protects against timing attacks
  const isValid = timingSafeEqual(
    Buffer.from(computedHash, 'hex'),
    Buffer.from(signatureHeader, 'hex')
  );

  if (!isValid) {
    return new Response('Invalid webhook signature', { status: 403 });
  }

  // 4. Safe to deserialize JSON after signature confirmation
  const payload = JSON.parse(rawBody);
  return new Response(JSON.stringify({ received: true }), { status: 200 });
}

Step 3: Reproduce the Exact Delivery Locally

Never test webhook changes directly against production servers. Capture the failing request headers and payload in an inspection tool such as Probe, then replay the identical byte sequence against your local environment using curl:

bash
curl -X POST "http://localhost:3000/api/webhooks/stripe" \
  -H "Content-Type: application/json" \
  -H "Stripe-Signature: t=1788102400,v1=982a1705646f90117d9e48..." \
  -H "User-Agent: Stripe/1.0 (+https://stripe.com/docs/webhooks)" \
  --data-binary @captured_webhook_payload.json

Using --data-binary rather than -d ensures that curl preserves exact line endings, whitespace, and Unicode sequences without normalization.

Step 4: Guard Against Retry Storms with Idempotency

When a downstream server encounters a brief hiccup or network partition, webhook providers like Stripe, Shopify, and GitHub automatically re-send events. Stripe retries failed deliveries up to several times over a 72-hour window using exponential backoff.

If your webhook endpoint is not idempotent, a repeated delivery can result in double charges, duplicated emails, or corrupt inventory records.

sql
-- Database schema pattern for webhook idempotency
CREATE TABLE processed_webhook_events (
  id VARCHAR(128) PRIMARY KEY, -- e.g. evt_1N4xZy2eZvKYlo2C
  provider VARCHAR(64) NOT NULL,
  event_type VARCHAR(128) NOT NULL,
  processed_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
  status VARCHAR(32) NOT NULL
);

Before processing an event, attempt an INSERT with an ON CONFLICT DO NOTHING clause. If the row already exists, acknowledge the delivery with an HTTP 200 OK without re-running the associated side effects.

Frequently Asked Questions

Probe Live Inspection
Ready to inspect incoming webhooks in real time?
Create a dedicated Probe endpoint to capture headers, verify raw byte payloads, and debug delivery failures before deploying to production.
Start debugging nowFree tier · Instant setup · TLS 1.3
Probe

Probe Team

Probe is a focused webhook debugging platform designed for engineering teams. We build telemetry and developer inspection tooling to eliminate integration guesswork.

All guides are regularly verified against Stripe, GitHub, Shopify, and RFC specifications.

More Webhook Guides
All articles
September 16, 20266 min read
A practical, battle-tested guide for capturing, verifying, and debugging Stripe webhooks locally without signature errors or payload corruption.
#Stripe#testing
Read guide
September 16, 20266 min read
Learn how to receive, inspect, and replay webhook events during local development using modern inspection endpoints and automated test fixtures.
#webhooks#local development
Read guide

Developer Webhook Telemetry

Start debugging your webhooks with Probe

Never guess what an API sent again. Real-time payload inspection, raw headers, and replay tools.