Webhooks are one of those bits of software that look trivial on a whiteboard and then quietly become one of the most fragile parts of your product. You draw an arrow from your system to the customer's system, label it "webhook", and move on to the interesting bit. Then six months later a customer is missing an order confirmation, nobody can work out why, and someone spends an afternoon staring at logs that were never designed to answer that question.
I have built webhooks into every SaaS product I have worked on, CampSuite pushing booking events out to accounting systems, Crocodile HR notifying a customer's own tools when someone joins or leaves. Every single time the first version was too simple, and every single time the fix was the same handful of decisions made properly instead of skipped. This is what I actually do now, learned the expensive way.
What a Webhook Actually Is, and Why an API Alone Does Not Cut It
A webhook is just an HTTP request your system sends to a URL the customer gives you, the moment something happens. A booking is confirmed, an invoice is paid, an employee leaves. Rather than the customer's system polling your API every few minutes asking whether anything has changed, you tell them the second it does.
The appeal is obvious. Polling is wasteful, it adds delay, and it puts load on your API for information that changes rarely. A webhook flips that relationship around, your system does the work once and pushes it out. The problem is that a webhook is a promise, not a simple request and response. You are promising to tell someone about an event, possibly more than once, possibly out of order, possibly when their server happens to be down. Most of the pain in webhooks comes from teams building them like a normal API call and only discovering the promise part when it breaks.
The Mistakes I See Small Teams Make Constantly
No Way to Prove the Payload Came From You
If your webhook is just a POST to a URL with a JSON body and nothing else, anyone who guesses or gets hold of that URL can send fake events to your customer's system. I have seen exactly this gap in more than one integration review, and it sits in the same category of risk I wrote about in securing a SaaS application without a dedicated security team. A webhook without a signature is not really an integration, it is an open door with your logo on it.
One Failed Delivery and the Event Is Gone
A customer's server has a bad five minutes, your webhook call times out, and the event just disappears. No retry, no record, no way for the customer to even know they missed something. This is the single most common complaint I hear from customers integrating with a platform, not the shape of the payload, just events vanishing into thin air the one time it actually mattered.
Processing the Webhook Synchronously
The other classic mistake is doing real work inside the request that delivers the webhook, updating a database, calling three other services, sending an email, all before returning a response. If any of that is slow, the sender's request times out and treats it as a failure, even though your system actually processed it fine. Now you have duplicate processing on the retry, stacked on top of a webhook system that was already fragile.
How I Actually Design Webhooks Now
Sign Every Payload
Every webhook I send now includes an HMAC signature in the header, generated from the payload and a secret unique to that customer. The receiving system checks the signature before doing anything with the payload. It costs almost nothing to build and it is the difference between a webhook and a security incident waiting to happen.
Retry With Backoff, and Keep a Record
A failed delivery gets retried, with the gap between attempts growing each time so you are not hammering a server that is already struggling. Just as important, every attempt gets logged with its outcome, so when a customer says they never got an event you can show them exactly what was sent, when, and what response came back. This is the same discipline I wrote about in monitoring and alerting for small SaaS teams, you cannot fix what you cannot see.
Make the Receiving End Idempotent
Because retries exist, the same event can arrive twice. I give every webhook event a unique ID and expect, and tell customers to expect, that processing the same ID twice should be safe and produce the same result. That one decision quietly removes an entire category of bug where a customer ends up charged twice or notified twice for the same thing.
Let Customers See and Replay Events
The single feature customers thank me for most is a simple log of every webhook event sent to them, with a button to resend it. It turns a support ticket that used to take a developer half a day into something a customer can fix themselves in thirty seconds. If you build nothing else from this list, build this one.
Version Your Payloads Before You Need To
The first time you need to change a webhook payload for customers already relying on the old shape, you will wish you had planned for it. I include a version field in every payload now and I add fields rather than changing or removing them wherever I possibly can. It is boring, unglamorous work, the same kind of forward thinking I talk about in multi tenant SaaS architecture lessons, and it saves a genuinely painful migration further down the line.
My Honest Take
Webhooks are not complicated technically. They are an HTTP request. What is complicated is respecting that you are making a promise to a system you do not control, over a network that will occasionally fail, to a server that will occasionally be down. Build for that from day one, signing, retries, idempotency, a replay button, and webhooks become one of the more reliable parts of your integration story rather than the thing generating the most support tickets.
If you are building integrations for a SaaS product and want a second opinion on how they are put together, that is exactly the kind of practical problem I help with through software development consulting. It is the same principle of getting the unglamorous bit right first that runs through The 28 Day Startup, because the features customers actually rely on are rarely the ones that show up on a roadmap slide.


