← Back to Blog
Guide webhooks debugging reliability devops

Debugging Webhook Delivery Failures: A Complete Guide

Webhooks fail silently. Your upstream service thinks the delivery succeeded, your app never received it, and you have no idea what went wrong. Here's a systematic approach to tracking down the problem.

JW

Jason Warner

February 14, 2026

Debugging Webhook Delivery Failures: A Complete Guide

Webhooks are one of those things that feel simple until something goes wrong. A third-party service fires an event, your endpoint is supposed to receive it, and somewhere in between nothing happens. No error. No log. Just... silence.

I've spent way too much time in this particular debugging loop, and I want to give you a structured way out of it.

Start With the Obvious: Is Your Endpoint Reachable?

Before blaming the upstream service, verify the basics.

DNS resolution: Can the sending service actually resolve your domain? This is more common than you'd think for internal or staging environments. Use a tool like dig or nslookup from an external network to confirm.

TLS certificate: Many webhook senders won't deliver to endpoints with invalid or self-signed certs. If you're testing locally, use something like ngrok or Cloudflare Tunnel rather than trying to get an upstream service to talk to localhost directly.

Firewall / security group: If your endpoint is behind a VPC or has IP allowlisting, confirm that the sender's IP range is permitted. Stripe, GitHub, and most major services publish their webhook IP ranges.

Port and path: Double-check the URL you registered. A trailing slash mismatch (/webhook vs /webhook/) can cause a redirect loop that returns a 301 instead of a 200, which many senders treat as a failure.

Check What the Sender Actually Received

Most webhook providers have a delivery log in their dashboard. Stripe has it under Developers → Webhooks. GitHub has it under your repository settings. Always check this first.

The delivery log tells you what HTTP status code your endpoint returned, how long it took, and whether there were retries. If the sender shows a 200 but your app didn't process the event, the problem is in your handler, not the delivery.

If the sender shows a non-200 response, look at the response body in the delivery log. Your application probably returned an error message that tells you exactly what went wrong.

If the sender shows a timeout (usually 30 seconds), your handler is too slow. Most webhook senders expect a fast acknowledgment — return 200 immediately and process the event asynchronously.

The Payload Might Not Be What You Think

Payload format issues are sneaky. The event arrives, your handler parses it, throws an exception on an unexpected field, and returns a 500. The sender retries a few times, gives up, and nobody notices.

Common culprits:

  • JSON property casing: Your model expects userId but the sender sends user_id. If your deserializer is strict about casing, the field silently maps to null and your code fails later with a null reference exception.
  • Numeric types: Stripe amounts are integers (cents), not decimals. GitHub timestamps are Unix epoch integers, not ISO 8601 strings. These type mismatches can cause silent deserialization failures.
  • Nested vs flat: Some services change their payload shape between API versions. If you recently updated an API version in your integration settings, compare the new payload shape to your model.
  • Unexpected fields: If your deserializer is set to fail on unknown properties, a new field the sender adds next month will break you.

A quick fix: log the raw request body (before parsing) to a string field whenever your webhook handler receives an event. This gives you forensic data for debugging without affecting processing.

The Timing Problem

Events that arrive during deployments are frequently lost. Your old process shuts down, the new one is starting up, and the event hits during that gap. If your webhook sender doesn't retry aggressively, it's gone.

Blue/green deployments help here. Health check endpoints that return 503 during startup let your load balancer drain traffic gracefully. But most teams don't have this wired up perfectly.

Another timing issue: rate limits. If you're receiving a burst of webhooks (say, Stripe processes a batch of invoices at renewal time), your endpoint might start returning 429s or timing out under load. The sender may or may not retry.

When You've Lost an Event: Recovery Options

If you've confirmed the event was never processed and the upstream sender isn't retrying anymore, you have a few options:

  1. Re-trigger from the source: Some services let you manually re-send specific events from their dashboard. Stripe supports this. GitHub does not for most events.
  2. Reconstruct from the sender's API: If you know what happened (a payment succeeded, an order was placed), you can often fetch the current state from the sender's REST API and replay it through your processing logic.
  3. Accept the gap and fix it manually: Sometimes the fastest path is just updating the database directly. Not ideal, but pragmatic for a one-off failure.

Using Bluejay Relay to Prevent This In the Future

The root cause of most webhook debugging pain is the same: you don't have visibility. The event came and went, and you have no record of the raw payload, the response your server gave, or how many times delivery was attempted.

Bluejay Relay gives you a permanent, searchable log of every webhook event — the raw payload, every delivery attempt, HTTP status, response body, and latency. When something goes wrong, you open the logs, filter by integration or time range, and see exactly what happened.

If an event failed, you can replay it directly from the log view with one click. For bulk failures (say, your endpoint was down for 30 minutes), the bulk replay feature lets you re-send a date range of events to your endpoint without any manual work.

On the paid tiers, you can also configure automatic retry with exponential backoff so transient failures are handled before they become a problem.


Stop flying blind. Set up Bluejay Relay free and get full visibility into every webhook delivery.

#webhooks #debugging #reliability #devops

See and recover every delivery.

Full delivery logs, real-time monitoring, one-click replay, and a dead-letter queue for the ones that fail. Free to start.