Webhook Not Receiving Data: A Step-by-Step Debugging Guide
When a webhook fails to deliver data, the issue typically lies in one of three areas: the sending provider, the network path, or the receiving server's configuration. Follow this systematic debugging guide to isolate and resolve the issue.
Step 1: Check the Provider's Delivery Logs
Most webhook senders (e.g., Stripe, GitHub, Shopify) provide a delivery log dashboard. Check this first to determine if the sender is attempting to dispatch the payload.
- **No attempts recorded:** The event trigger configuration is incorrect on the provider side. Verify that the specific events you want to monitor are selected.
- **Failed attempts (Red/Error status):** Note the HTTP status code returned by your server (e.g., 400, 403, 404, 500, or 502).
- **Connection timeouts:** Your server is not responding within the provider's timeout limit (usually 3 to 15 seconds).
Step 2: Isolate the Endpoint Using a Request Inspector
Rule out your server code by routing the webhook to a public request inspector like Webhook.site or RequestBin.
- Generate a temporary URL from Webhook.site.
- Update your webhook provider's destination URL to this temporary URL.
- Trigger the event.
If the inspector receives the data, your provider is working correctly; the issue lies in your network routing, firewall, or application code.
Step 3: Verify Network, DNS, and SSL/TLS Settings
Webhook providers require secure, publicly accessible endpoints. Verify the following network requirements:
- **HTTPS Requirement:** Most providers reject non-SSL (HTTP) endpoints or invalid/expired SSL certificates. Self-signed certificates are rarely accepted.
- **Port Restrictions:** Ensure your server listens on standard ports (`80` or `443`). Many providers block custom ports like `8080` or `5000`.
- **Localhost Debugging:** If debugging locally, use a tunneling tool like `ngrok` or `Localtunnel` to expose your local port to a public HTTPS URL:
ngrok http 3000
Step 4: Inspect Firewall and Reverse Proxy Logs
If the provider logs show a timeout or a 502/504 Bad Gateway, your server or reverse proxy (Nginx, Apache, Cloudflare) may be blocking the incoming traffic.
- Check your Nginx/Apache access and error logs (usually located in `/var/log/nginx/` or `/var/log/apache2/`).
- Verify that your firewall (UFW, AWS Security Groups) allows incoming traffic on port 443 from the provider's IP ranges.
- Disable Web Application Firewall (WAF) rules temporarily to see if they are flagging the webhook payload as suspicious.
Step 5: Debug Application Code and Payload Parsing
If your server receives the connection but returns a 400 (Bad Request) or 500 (Internal Server Error), the issue is in your application logic. A common culprit is failing to parse the incoming request body correctly.
Here is a robust Node.js/Express template designed to log incoming headers and raw body data for debugging:
const express = require('express');
const app = express();
// Use express.json() but preserve raw body for signature verification if needed
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString();
}
}));
app.post('/webhook', (req, res) => {
console.log('--- Incoming Webhook ---');
console.log('Headers:', req.headers);
console.log('Body:', req.body);
// Always return a 200 OK immediately to acknowledge receipt
res.status(200).send('Webhook received');
});
app.listen(3000, () => console.log('Webhook receiver listening on port 3000'));
Ensure your endpoint returns a 200 OK or 202 Accepted status code immediately before running heavy background processes, as delayed responses trigger timeout errors and retries from the provider.
Need this done fast? order a fix on Kwork (https://kwork.com/scripting/52991008/integrate-your-services-api-webhooks-crm-and-payments).
Top comments (1)
Solid debugging flow. One pattern I keep seeing with webhook failures is that people often focus on transport first, but a lot of real failures happen after the request reaches the endpoint especially around payload structure, header formatting, or authentication.
In form-to-API workflows, I’ve seen cases where the webhook fires successfully, but the receiving API rejects it because it expects nested JSON, specific content types, or bearer tokens in a very strict format.
While working on the plugin called Contact Form to Any API, this came up a lot in CRM integrations. The fastest debugging path was usually: inspect the raw payload, compare it against the API schema, verify auth headers, then replay the exact request in Postman. That usually isolates the problem much faster than checking infrastructure first.