The order that shipped four days late
A customer pays on Stripe at 11:04 on a Tuesday. The charge succeeds. The confirmation email goes out. And then nothing happens, because the webhook that was supposed to tell your fulfillment system "hey, go pack this" never made it through. Nobody notices until Friday, when the customer emails asking where their order is.
If you run an SMB with any kind of connected stack (Stripe talking to your order system, Shopify talking to your 3PL, your CRM talking to your billing tool), you've lived some version of this. Silent webhook failures are the culprit almost every time, and they don't happen the way you'd expect a bug to happen. There's no error screen, no downtime, no ticket. They're a slow leak: a handful of missed events a week, invisible until someone downstream notices a gap and by then the trail is cold.
Most founders don't think about webhook reliability until it's already cost them a customer, a chargeback, or a very annoyed ops person doing manual reconciliation in a spreadsheet every Monday morning. Worth thinking about before that.
Why silent webhook failures happen in the first place
A webhook is a promise with no guarantee attached. The sending system (Stripe, Shopify, HubSpot, whoever) fires an HTTP request at your endpoint and waits for a 200. If your server is mid-deploy, or the database connection pool is maxed out, or your handler throws on a null field it didn't expect, you return a 500 or you time out. Most providers will retry a few times, on their own schedule, with their own backoff. Stripe retries for up to three days. Some tools retry twice and quit. A few don't retry at all.
Here's the part that actually bites: once retries are exhausted, the event is just gone. It sits in a dashboard log somewhere in Stripe's UI that nobody on your team checks. Your system has no record it was ever supposed to happen. There's no missing-order flag, no red banner, nothing. The absence of a record looks exactly like the absence of an event.
This is different from most bugs. A broken button gets reported the same day. A missing webhook gets discovered whenever someone happens to reconcile two systems by hand and spots the gap — which, for a lot of small teams, is never, or only after a customer complains.
The root causes are boring and specific:
- Your endpoint processes the event synchronously and something in that chain is slow or flaky (an email send, a third-party API call, a lock on a busy table), so you time out under load even though the logic itself is fine.
- You don't verify signatures or dedupe, so a retried event either gets rejected outright or processed twice, corrupting downstream state.
- Deploys happen without any drain period, so requests land on a instance that's mid-restart.
- There's no dead-letter queue, no failure log, no alert. The system fails closed and silent instead of failing loud.
Why the usual fixes don't hold
The first instinct is almost always "add a retry" or "just add logging." Both help a little and neither solves it.
Bumping retry counts on the provider side doesn't help if the failure is deterministic — a bug in your handler will fail the same way on attempt one and attempt six. Adding console logs helps you debug after the fact, assuming you go looking, but nobody's paging themselves to read logs for an event that technically never arrived.
Routing everything through Zapier or Make feels like it fixes reliability because now there's a "history" tab you can check. In practice it just moves the blind spot one layer over — you've traded "no visibility into Stripe's retries" for "no visibility into Zapier's retries," and you've added a third-party dependency with its own outages and its own silent task failures. It's a real tool for prototyping an integration in an afternoon. It's a weak foundation for anything a customer-facing process depends on.
The other common move is manual reconciliation: someone pulls a Stripe export every week and cross-checks it against orders in the CRM. This works, technically, the same way checking your bank statement line by line works. It doesn't scale past a few dozen transactions a week, it's exactly the kind of task people quietly stop doing when they get busy, and it only catches problems after the damage — the late shipment, the missed invoice — is already done.
None of these fixes address the actual gap: there's no durable, queryable record that an event was expected, arrived, and was processed. Without that record, you're always debugging from absence, which is the hardest kind of debugging there is.
What a webhook setup that doesn't lose events actually needs
This isn't complicated engineering, but it does need to be deliberate. The checklist we use when we build or audit a client's integration layer:
- Acknowledge fast, process async. Your endpoint's only job on receipt is to verify the signature, write the raw event to a table, and return 200. Anything expensive — updating three systems, sending emails, calling other APIs — happens in a background worker that reads from that table. This alone kills most of the timeout-driven failures.
- Make every event idempotent. Store the provider's event ID and check it before processing. Retries and duplicate deliveries become harmless instead of corrupting data.
- Give failures somewhere to land. A dead-letter table or queue for events that fail processing after N attempts, with the actual error attached — not just "failed," but why.
- Alert on the gap, not just the error. The scariest failure mode is the request that never arrives at all — a DNS hiccup, a firewall rule, a provider outage. Track expected volume per source and alert when it drops to zero, not just when you see 500s in your own logs.
- Keep a replay path. If you find a gap, you need a button, not a ticket to engineering, to reprocess a specific event or a date range once the underlying issue is fixed.
Tradeoff worth naming honestly: this is more infrastructure than a five-person company strictly needs on day one. If you're processing a couple hundred webhooks a month across two integrations, a simple table plus a scheduled job checking for stale unprocessed rows is enough — you don't need SQS or a message broker. Past a few thousand events a month or five-plus event sources, the coordination overhead of doing it by hand outweighs the setup cost of a real queue (SQS, Cloud Tasks, or similar). Match the tooling to the volume, not to what sounds impressive in an architecture doc.
Where this connects to automation and AI
This is the part people want to skip to, and it's exactly why so many AI rollouts on top of integrations underdeliver. An AI agent that's supposed to catch anomalies, or auto-resolve failed payments, or flag suspicious order patterns, needs a trustworthy event history to reason over. If your webhook layer silently drops 2% of events, any agent built on top of that data is reasoning over a dataset with invisible holes in it — and it will confidently produce wrong answers, because nothing tells it the gap exists.
Once you have structured, logged, replayable events — every webhook recorded with its outcome, timestamp, and retry history — an AI agent becomes genuinely useful here. It can triage a spike in dead-letter events and tell you whether it's a transient provider blip or a schema change that needs a code fix. It can summarize "here's what actually happened to order #4521" across five systems in a sentence instead of you tracing it by hand. That's a real, unglamorous win. But it's downstream of the plumbing, not a replacement for it. No agent fixes a webhook endpoint that returns 500 under load.
Start with the plumbing
If you recognize the four-days-late order, or you've got a spreadsheet somewhere that exists purely to catch what your systems missed, that's the signal. Not "we should look into AI for ops" — "we should find out why our systems don't agree with each other in the first place."
We run a free 30-minute Process Teardown where we map one of your actual workflows, trace where it's leaking time or breaking silently, and show you the hours it's quietly costing each month. No pitch, no obligation. You can see the kind of disconnected-tool-to-one-system work we've done for other teams in our case studies.
0 Comment