Webhook
Tool
A method where the side something happened on sends a notification first, to an address the other side registered in advance.
Why it exists
For a long time the only way to learn that something had happened in someone else's system was to keep asking. To find out whether a payment was approved, you call the provider's lookup endpoint every minute. That's 1,440 calls a day, of which a handful actually carry news.
The cost arrived in three forms. More than a thousand pointless requests a day make both servers work for nothing; the rate limit capping how many calls one client may send in a window starts rejecting the requests that do matter; and after all that, the notice is still up to a minute late. Shorten the interval to ten seconds and the requests multiply by six while the delay becomes ten seconds. There's no setting where both numbers are good. The two costs trade against each other and neither one goes away.
So the direction flipped. Instead of the asking side knocking continuously, the side where the event occurs sends to an address it was given ahead of time. Register the address once and, after that, traffic happens only when something happens. The quiet hours cost nothing at all.
What it solves
Flipping the direction removes three things at once: the delay between event and notice, the requests exchanged while nothing is happening, and the rate-limit budget those requests consume.
In exchange, the receiving side has work to do. In practice this is where nearly all the difficulty lives.
- Build and register a receiving address. That address has to be open on the internet, which means anyone can knock on it. So the sender includes a signature computed from the body and a shared secret, and the receiver recomputes that signature and only believes the content once it matches.
- Acknowledge fast and defer the processing. Most senders treat a missing response after a few seconds as a failure and resend. Store the payload on arrival, return success, and move the real work to a job running behind. A slow handler turns into a flood of duplicates, which is the failure mode people meet first.
- Make repeated delivery of the same event harmless. Retries are normal behavior, so duplicate arrival is a premise rather than an exception. The property of producing the same result no matter how many times a request arrives is idempotency; you get it by recording the unique event id that arrives with each notice and returning success immediately for ids you've already processed.
- Don't trust ordering. When an approval and a cancellation happen back to back, the cancellation can arrive first. Judge from the timestamp or version value carried in the body, and discard an older event if you've already applied a newer state. Reordering is rare enough to survive testing and common enough to happen in production.
- Add a lookup path to fill in what you missed. If your server was down for 30 minutes, the notices for that window exhaust their retries and vanish. So a daily job pulls the other side's list and reconciles it against yours. Nothing about the notification itself tells you it went missing.
- Keep failed notices somewhere and give yourself a way to reprocess them. Without that screen, the only recourse when something breaks is asking the other company to resend, which takes a support ticket and a day.
Alternatives
Four approaches address the same need differently.
- Continuing to poll. Easiest to build, and entirely under your control. Where events are rare, a minute of delay is fine, or the other side offers no notifications, this is what remains.
- Holding a connection open. A WebSocket keeps a connection alive so either side can speak at any moment. It fits well between a screen and a server; between two servers, holding the connection is expensive.
- Streaming one direction from server to client. The connection stays open but only the server talks, which is simpler than a WebSocket and fits pushing notices onto a screen immediately.
- Publishing onto a queue. Between services inside one company, putting events on a message queue and letting interested parties pull works better. The event waits in the queue even while the consumer is down, so nothing is lost.
Three questions decide it: whether the boundary being crossed is between companies, how many seconds of delay are acceptable, and whether an event can be missed. Crossing a company boundary, needing to know within seconds, and not being allowed to miss anything is where this method belongs; inside one boundary, a queue is usually better, because you control both ends and can keep the event until it's handled.
How it sounds at work
"We're polling payment status every minute. Let's switch to webhooks."
Flip the direction of the asking.
"We process the body without verifying the signature. A forged request would go through."
Naming the risk of an open address.
"The same event arrived three times and got processed three times. This has to be idempotent."
Retries are the premise, not the exception.
Pagedeck moved its payment provider integration to this method. Theo looked at the polling logs first: 1,400 requests a day, thirty of which carried news. After the switch, traffic came to thirty calls a day, and the time from payment success to the user seeing it dropped from an average of 28 seconds to under one.
There was one incident in the first week. Twelve notices arriving during a four-minute deployment gap disappeared. So a nightly job was added to pull the day's payment list and reconcile it. That reconciliation turned out not to be optional in an architecture that trusts notifications. Four minutes of downtime is an ordinary deployment, not an incident.
What people get wrong
The most common belief is that an arriving notice can be taken at face value. It came from the other party, so it looks trustworthy. But the address is open on the internet, and anyone who knows it can construct a request in the same shape. Forge a payment-success notice and paid features unlock without money changing hands. Verifying the signature, and reconfirming the amount and status through the other side's lookup, is the baseline.
The other frequent belief is that notifications make the lookup endpoint unnecessary. It looks like receiving the same information twice. But notices arrive only while your server is in a state to receive them. Deployments, outages, and network problems guarantee windows where you can't, and a lookup is the only way to fill those windows. The two paths are a pair, not substitutes.
Easily confused with
| Term | How the connection is held | How it differs from a webhook |
|---|---|---|
| WebSocket | The connection stays open | Either side can speak at any moment and the delay is shorter. In exchange the connection has to be held, which suits a screen and a server better than two servers |
Where to go next
Last updated 2026-09-16