Your webhook broke. Something downstream stopped working — new customers aren't getting onboarding emails, your CRM isn't updating, your Slack alerts went quiet. You need to find the problem fast. This is the exact debugging process, tool by tool, that finds the issue in under ten minutes.
This guide assumes the webhook was working before and has now stopped. If you're setting up a webhook for the first time and it's never worked, start at Step 3 — URL and authentication problems are the most common cause of a webhook that never fires at all.
The four places a webhook can break
Every webhook failure falls into one of four categories. Knowing which category your problem lives in cuts your debugging time in half.
Work through these in order. Most webhook failures are authentication or URL problems. Start there.
SOURCE TOOL → [fires event?] → WEBHOOK REQUEST → [reaches URL?] → AUTHENTICATION → [passes?] → PAYLOAD → [processed?] → DESTINATION TOOL
Check the delivery logs first
Before touching any settings, go to the delivery logs in your source tool. Every major platform keeps a log of every webhook attempt, whether it succeeded, and what the response was. This tells you exactly where the failure is happening.
Stripe
Stripe Dashboard → Developers → Webhooks → click your endpoint → Recent Deliveries tab What to look for: ✓ Green checkmark = delivered successfully ✗ Red X = delivery failed — click it to see the response code and error message Response codes that tell you the problem: 200 = delivered fine (problem is downstream, not here) 400 = your endpoint rejected the payload (payload problem) 401 / 403 = authentication failed (key or secret problem) 404 = endpoint URL not found (URL problem) 500 = your server errored on receipt (your code problem) timeout = your server took too long to respond
Stripe retries failed webhooks automatically — once an hour for 24 hours, then once a day for three days. If you fix the underlying issue, Stripe will automatically retry delivery of any events that failed in the last 72 hours. You don't need to manually resend in most cases.
Zapier
Zap → Task History (clock icon on the left sidebar) Filter: Last 7 days, show errors What to look for: - Tasks with status "Error" — click for the exact error message - Tasks with status "Stopped" — your zap hit an error threshold and auto-paused - Zero tasks when there should be some — the trigger isn't firing at all Check the zap is actually turned on: The toggle at the top of the zap editor. Zaps auto-pause when they hit repeated errors or when you hit your task limit for the month.
HubSpot
Settings → Integrations → Private Apps → [your app] → Logs tab Or for native integrations: Settings → Integrations → Connected Apps → [integration] → Activity What to look for: - Failed API calls with error codes - Authentication errors (usually means token needs reconnecting) - Property mapping errors (field names changed or no longer exist)
Custom webhooks you've built yourself
Check your server logs for the endpoint URL. If you're using Vercel: Dashboard → your project → Functions → Logs If you're using AWS Lambda: CloudWatch → Log Groups → find your function If you're on a VPS: tail -f /var/log/nginx/access.log | grep [your webhook path] Look for: incoming requests hitting the endpoint. No requests at all = the source isn't sending. Requests with errors = your code is failing on receipt.
Check authentication
If your logs show 401 or 403 errors — or if the source tool shows no delivery attempts at all — authentication is almost certainly the problem. This is the most common cause of webhook failures that appear with no warning.
API keys
Webhook secrets and signatures
Many tools sign their webhook payloads with a secret so your endpoint can verify the request is genuine. If this secret has changed on the source tool's end, every incoming request will fail signature verification and get rejected.
Stripe → Developers → Webhooks → [your endpoint] → Signing secret → Reveal If you've rotated this secret, every endpoint consuming this webhook needs the new value. In your .env file or environment variables: STRIPE_WEBHOOK_SECRET=whsec_[new value here]
OAuth tokens
OAuth token expiry is one of the most common causes of silent webhook failures. Many platforms expire tokens after 60–90 days if not refreshed. When they expire, the integration stops silently — no error email, no alert, just silence. The fix is to disconnect and reconnect the integration, which generates a fresh token. Do this in the source tool under Settings → Connected Accounts or equivalent.
Check your endpoint URL
A URL problem is the second most common cause. Your endpoint URL may have changed without the source tool being updated.
Common causes of URL changes:
- Redeployment changed your URL structure
- You moved from HTTP to HTTPS (or vice versa — always use HTTPS)
- A trailing slash was added or removed
- Your domain changed or a subdomain was removed
- Vercel or Netlify generated a new preview URL and someone used that instead of the production URL
Use webhook.site to create a temporary endpoint in one click. Point your source tool at that URL temporarily. If events start appearing there, your source tool is working fine and the problem is with your actual endpoint. If nothing appears, the problem is upstream — the trigger isn't firing at all.
Check the payload
If your logs show 400 errors — the request is reaching your endpoint but being rejected — the payload is likely the problem. This usually happens when:
- An API has been updated and field names have changed
- You updated your receiving code and it no longer accepts the old payload format
- A required field is missing or null
- A data type changed (string became integer, etc.)
Inspect the actual payload being sent
Method 1 — webhook.site Create a temporary endpoint at webhook.site. Point your webhook there temporarily. Trigger a test event. webhook.site shows you the full raw payload — headers, body, everything. Compare this to what your endpoint expects. Method 2 — Requestbin (pipedream.com/requestbin) Same approach, slightly different interface. Good for capturing multiple events and comparing them side by side. Method 3 — ngrok (for local development) ngrok http 3000 Creates a public URL that tunnels to localhost. Lets you test webhooks against your local development environment in real time.
Check the source tool's API changelog
If the payload looks different from what you expect, the source tool may have updated their API. Check:
Stripe changelog: stripe.com/docs/upgrades Zapier check the trigger step for field changes HubSpot developers.hubspot.com/changelog
Check the trigger — is the source even firing?
If your logs show zero delivery attempts — no requests, no errors, just silence — the problem is upstream. The source tool isn't sending anything at all.
Force a test and verify end to end
Once you think you've found and fixed the issue, don't just assume it's working. Test it deliberately end to end.
Stripe: Dashboard → Developers → Webhooks → [your endpoint] → Send test webhook Select the event type → Send Zapier: Open the zap → Test trigger → confirm sample data loads → Test action → confirm it completes without error HubSpot: Settings → Integrations → Private Apps → [your app] → Test tab Custom webhook: Trigger the actual source event manually: - Create a test customer with a Stripe test card - Submit a test form entry - Trigger the event through the source tool's UI Then immediately check the destination tool for the expected result.
When you genuinely can't find the problem
If you've worked through all six steps and still can't identify the cause, here's the honest escalation path:
How to make sure this never happens again
Fixing this one webhook is the short-term win. The longer-term problem is that you have no early warning system — you're finding out about failures after they've already caused damage.
The minimum you should set up after fixing this:
Never debug a webhook blind again.
Stakmap monitors your integration stack automatically — and tells you in plain English what broke, why, and exactly how to fix it. Join the waitlist for early access.
Get early access — it's free →Quick reference — error codes and what they mean
| Error Code | What it means | Where to look |
|---|---|---|
| 200 | Delivered successfully | Problem is downstream of your endpoint |
| 400 | Bad request — payload rejected | Check payload format and required fields |
| 401 | Unauthorised — authentication failed | Check API key and webhook secret |
| 403 | Forbidden — insufficient permissions | Check API key scopes and permissions |
| 404 | Endpoint not found | Check webhook URL is correct and live |
| 405 | Method not allowed | Endpoint exists but wrong HTTP method |
| 429 | Rate limited | Check rate limits on source and destination |
| 500 | Server error on your end | Check your server logs for the exception |
| 503 | Service unavailable | Check source tool status page |
| Timeout | Server too slow to respond | Endpoint must respond in under 30 seconds — queue processing for slow operations |
Webhook debugging is almost always one of these six steps. The logs tell you which one. The faster you learn to read delivery logs, the less time you spend wondering why something stopped working.
If this took more than ten minutes, it's usually because the logs weren't checked first. Start there every time.