A webhook is an HTTP request that one application sends to another when something happens. Instead of asking every minute whether an invoice was paid, the payment provider posts to a URL you gave it the moment it is.
The concept takes one sentence and the operational reality takes four: the request can fail, anybody can send one, the receiver must be reachable from the internet, and retries mean the same event arrives twice.
- Webhooks are HTTP POSTs from the sending application to a URL you registered
- They replace polling, and invert which side initiates the connection
- Delivery is not guaranteed, so senders retry and receivers see duplicates
- An unverified endpoint is a public URL anybody can post to
- The receiver must be reachable from the internet, which is the usual blocker
On this page
Against pollingWebhooks against polling
The problem webhooks solve is the cost of asking.
Without webhooks, an app that needs to know about an event checks on a schedule. Every minute, send an API request to the payment provider asking whether anything was paid.
Almost every check returns no data, the answer is stale by up to a minute, and the provider carries the load of answering thousands of pointless questions. That is polling, and it is what a scheduled job usually exists to do.
Webhooks invert it. You register a URL, the provider automatically sends the data to it when something happens, and no API request is sent in between. The webhook arrives in about a second, no requests are wasted, and the load disappears.
The cost of that inversion is the whole rest of this page. Polling is easy to operate because your application is the client and initiates everything: it decides when to ask, it sees the failure immediately, and it can just ask again.
Webhooks make the other party the client and your application the server, which means the failure happens on their side, in their retry queue, where you cannot see it.
| Polling | Webhook | |
|---|---|---|
| Who initiates | You | The sender |
| Latency | A whole interval | About a second |
| Wasted requests | Most of them | None |
| Needs an inbound path | No | Yes, from the internet |
| Missed event recovery | Ask again | Depends on their retries |
| Duplicate handling | Rarely needed | Required |
The fourth and fifth rows are why plenty of mature integrations still poll, and why the good ones do both: webhooks for speed, and a periodic reconciliation poll to catch whatever the webhooks lost.
The payloadWhat is in the payload
Most answers to what is a webhook stop at the arrow between two apps. The payload is the part a handler actually deals with.
A webhook is an HTTP POST, so it carries headers and a body, and the receiving software reads both. The headers identify the delivery. The body carries the data about the event.
Providers put the event name, a unique delivery id and the signature in headers, so a receiver can route and verify a request before it parses anything. GitHub's webhook documentation lists X-GitHub-Event for the name of the event that triggered the delivery and X-GitHub-Delivery for a GUID that identifies it.
The same page documents X-Hub-Signature-256 as the HMAC hex digest of the request body, generated with SHA-256 and the configured secret. Header names differ from one provider to the next, which is why a handler written against one API rarely reads another without changes.
JSON is the usual body format. Form encoded and XML still turn up in older software. Whatever the encoding, the data in the body answers three questions: what happened, when it happened, and which object it happened to.
Thin payloads send an identifier and little else: the event type, an event id, a timestamp and the id of the affected record. The app reads the current state back from the sender's API before acting. That is more requests, and the data it acts on is current.
Fat payloads send the whole object. One request and the receiver has everything, which is why automation platforms prefer them. The data is a snapshot from the moment the event fired, so a delivery that arrives after an hour of retries may no longer match what the provider holds.
Either way, read the provider's payload reference before writing the handler. Field names, nesting and which fields are optional are their decision, and the same event type can carry different data depending on how the object was created.
What breaksThe four things that break one
The complete answer to what is a webhook is not the arrow. It is the arrow plus these four, because three of them happen after the sender has done everything correctly.
Delivery fails and nobody tells you. A webhook is a single HTTP POST to your server. If the endpoint is down, slow, or returns a 500, that delivery failed.
What happens next is entirely the sender's policy: most retry with an exponential backoff for some hours and then give up, some retry a fixed number of times, a few do not retry at all. Read that policy before relying on it, because after the last attempt the event is gone and nothing on your side knows it existed.
Anybody can post to the URL. A web endpoint that accepts webhooks accepts them from whoever finds the address. Without verification, a forged POST saying an invoice was paid is indistinguishable from a real one. This is the failure that matters most and it is the easiest to fix.
The same webhook arrives more than once. A retry does not know whether the previous attempt failed before or after your app processed the data. A response that timed out may well have been processed. So duplicates are normal traffic, not an error condition, and every handler has to be safe to run twice on the same event.
Webhooks arrive out of order. Two events sent a second apart can arrive in either order after a retry, so a handler that assumes sequence will corrupt state. Use the timestamp or version in the payload rather than arrival order.
VerificationVerifying that it really came from the sender
Three approaches, in increasing order of how much they actually prove.
A shared secret in the URL is the weakest and the most common. The web path contains a random string only the sending server knows. It works until the URL appears in a log, a referrer header, a proxy record or a screenshot, and URLs end up in all of those.
An HMAC signature is the standard answer for webhooks. The sender computes a hash of the request data using a secret you both hold, and puts it in an HTTP header. You compute the same hash and compare. A forged request fails because the attacker does not have the secret, and a modified body fails because the hash covers it.
Three details decide whether an HMAC check is worth anything. Compare with a constant time comparison rather than string equality, because a naive comparison leaks the correct value one byte at a time.
Include the timestamp in what is signed and reject anything older than a few minutes, or a captured request can be replayed forever. And verify before parsing, because the point is to reject untrusted input before your code touches it.
Mutual TLS is the strongest and the rarest, because both sides need certificate infrastructure. Where a provider offers it and the data justifies it, it removes the shared secret problem entirely.
Whichever is used, the endpoint should also be boring: no information in the response body, the same 2xx for everything accepted, and no detail in the error that tells a prober what it got wrong.
ReachabilityThe reachability problem
This is the constraint that decides whether a webhook is even possible, and it is the one developer documentation skips because it is somebody else's job.
A webhook requires the sending system to reach your endpoint from the internet. That means a public DNS name, a web server listening on 443, a valid certificate, and a firewall that permits inbound HTTP traffic to that one path. For a SaaS receiver this is free. For an app inside a corporate network it is a project.
The options, in the order they are usually considered.
Publish the endpoint properly, behind a reverse proxy or an existing ingress, with the path restricted and everything else on that host closed. Correct, and it is a change most security teams will want to review.
Use the provider's IP ranges, if they publish them, to restrict who can reach the path. Useful defense in depth, not a substitute for the signature, and it needs maintaining when their ranges change.
Receive in the cloud and forward inward, which is what most automation software does: a public endpoint you do not run accepts the webhook and pushes the data into your network over a connection you initiated.
Or do not receive at all, and poll instead. For an internal system with no inbound path and no appetite to build one, polling every few minutes is often the honest answer, and it does not need a firewall change or a signature scheme.
The responseResponding correctly
The response contract is narrower than most implementations assume.
Answer fast. Sending servers time out, commonly within a few seconds, and a timeout counts as a failure that triggers a retry. Anything slow belongs behind a queue: accept the data, write it somewhere durable, return 2xx, and do the work afterward.
Return the right status. A 2xx means received. A 4xx usually tells the sender not to retry, because the request was malformed and will be malformed again. A 5xx asks for a retry. Returning 200 to something you could not process is how event data disappears silently.
Do not do the work in the handler. The single most common design mistake in webhooks. A handler that calls three other APIs before responding will time out under load, the sender will retry, and the retries will pile onto a system that is already struggling.
Webhooks and APIsWebhooks and APIs, and which way the call goes
Webhooks and APIs are not alternatives. They are the same HTTP mechanics pointed in opposite directions, and most integrations use both.
With an API, your system is the client. It sends a request when it wants data, waits for the response, and reads whatever came back. Nothing happens until your code asks, so your code controls the timing, the rate and the error handling.
With a webhook, the sender is the client and your endpoint is the server. The provider automatically sends the data when the event happens, and your system finds out without asking. That is why webhooks get called reverse APIs, and why they are described as event driven rather than request driven.
The practical split follows from that. Webhooks tell you something changed, quickly and with a small payload. The provider's APIs answer the follow up questions: read the full record, check the current balance, list what you missed while the endpoint was down.
It also explains the quota arithmetic. Polling an API every minute spends requests whether or not anything happened, and many providers cap those requests per hour. Webhooks spend none of that budget, and the reconciliation poll that catches missed data can run every few hours instead of every minute.
PitfallsWhere webhook integrations go wrong
No signature verification. The endpoint works in testing, ships, and is a public write API for anybody who finds the URL.
Assuming exactly once delivery. There is no such thing over HTTP. Handlers must be idempotent, usually by recording the event id and ignoring one already seen.
Doing the work synchronously. Covered above and worth its own line, because it is the failure that only appears under load, which is the worst time to find it.
No visibility into what was missed. If the sending application exhausted its retries, nothing tells you. A periodic reconciliation against their API is the only way to know, and every serious automation has one.
Trusting the payload data over the source. Even a correctly signed webhook only proves the sender sent it. If the data says an invoice was paid for 40,000, read the record back from their API before acting on a number that large.
Forgetting the secret is a credential. It sits in configuration, it is shared with a third party, and it needs rotating like any other. Most providers support two active secrets during a rotation, which is the only way to do it without dropping events.
ComparisonWebhook, polling, a message queue, or server-sent events
| Criterion | Webhook | Polling | Message queue | Server-sent events |
|---|---|---|---|---|
| Who initiates | The sender | You | You, to the broker | You, once |
| Latency | About a second | An interval | About a second | Immediate |
| Needs an inbound path | Yes | No | No | No |
| Delivery guaranteed | No | You control it | Yes, by the broker | No |
| Ordering guaranteed | No | Yes | Usually | Yes |
| Duplicates | Expected | Rare | Possible | Rare |
| Works between organizations | Yes | Yes | Rarely | Rarely |
The third row against the last is the trade that decides most designs. Webhooks are the only option here that works across an organizational boundary without either party holding a connection open, and the price of that is an inbound path and everything on this page.
A message queue is better at delivery in every way and only exists inside one estate.
FAQFrequently asked questions
What is a webhook?
An HTTP request, almost always a POST carrying the event data in a JSON body, that one app sends automatically to a URL you registered when a specific event happens. It replaces asking on a schedule.
What is the difference between webhooks and an API?
Direction. With an API your application is the client and calls them when it wants something. With webhooks they are the client and call your server when something happens. Most providers offer both, and the webhook usually carries a summary of the data while the API carries the detail.
Are webhooks secure?
Only if verified. An endpoint without signature checking accepts a POST from anybody who knows the URL, and a forged event is indistinguishable from a real one.
How do I verify a webhook is genuine?
Check the HMAC signature in the header against a hash you compute from the body and the shared secret. Compare in constant time, include a timestamp in the signed data and reject old requests, and verify before parsing the body.
Why does the same webhook arrive twice?
Because a retry cannot tell whether the previous attempt was processed. A response that timed out may have succeeded on your side. Duplicates are normal, and handlers have to be safe to run twice.
Do webhooks guarantee delivery?
No. The sender retries according to its own policy, usually with backoff for some hours, and then stops. After that the event is gone, which is why a reconciliation poll is worth having.
Do webhooks arrive in order?
No. Two events sent a second apart can arrive in either order once a retry is involved. Use the timestamp or version in the payload rather than the order of arrival.
What status code should a webhook endpoint return?
2xx for accepted, quickly. 4xx to tell the sender not to retry a malformed request. 5xx to ask for a retry. Never 200 for something you could not actually process.
How fast does a webhook endpoint have to respond?
Faster than the sender's timeout, commonly a few seconds. Accept the event, store it durably, return 2xx, and do the real work asynchronously.
Can I receive webhooks inside a corporate network?
Only with an inbound path from the internet: a public name, a listener on 443, a certificate and a firewall rule. Where that is not available, either receive in the cloud and forward inward, or poll instead.
Should I restrict webhooks to the provider's IP addresses?
It is useful defense in depth and not a substitute for the signature. Ranges change, so it needs maintaining, and an IP allowlist proves where a request came from rather than that it is genuine.
What happens if my endpoint is down for an hour?
It depends entirely on the sender's retry policy, which is why reading it matters. Some will still be trying, some will have given up, and the events from the ones that gave up are only recoverable through their API.
How do I rotate a webhook secret?
Use the provider's dual secret support if it exists: add the new secret, accept either signature for a period, then remove the old one. Swapping in one step drops every event in flight.
Should I use webhooks or polling?
Both, in most serious integrations. Webhooks for the latency, and a periodic reconciliation poll to catch what the webhooks lost, because nothing about webhook delivery is guaranteed.
How do webhooks work?
You register a URL with a service. When an event happens, the service automatically sends an HTTP POST to that URL with the data in the body, usually as JSON. Your endpoint replies with a 2xx status to confirm receipt. How webhooks work is the reverse of polling: the sender calls you.
What does webhook security involve?
Webhook security rests on three checks. Accept requests only over HTTPS. Verify the webhook signature, an HMAC of the body made with a shared secret, before trusting anything. Reject old timestamps so a captured request cannot be replayed. The endpoint is public, so assume strangers will send to it.
How does a webhook retry work?
If your endpoint does not return a 2xx status in time, most providers retry with growing delays for hours or days, then give up. A webhook retry can deliver the same event twice, so handlers must be idempotent. Store the event ID and ignore one you have already processed.
Keep readingRelated concepts
Read next · Network security What Is a Firewall? The inbound rule the receiver needs, and the reason a corporate network makes this a project. Open this next14 min- Operations · 11 min What Is a Cron Job? What a webhook replaces: the scheduled job that asks every minute and is told nothing almost every time.
- Cryptography · 11 min Hash Functions, and Why the Right One Depends on the Job The HMAC underneath webhook signature verification, and why a constant time comparison matters.