How Webhooks Work
A webhook lets one service tell another service when something happens. Instead of your app repeatedly asking for updates, the other service sends an HTTP request to your webhook endpoint when an event occurs.
What happens when a webhook is sent?
- Something happens inside an external service — a payment succeeds, a message arrives, someone pushes code.
- The service creates an event: a small piece of data describing what changed.
- It sends that event in an HTTP request to your webhook endpoint, a URL your backend exposes for exactly this.
- Your backend verifies that the request is authentic before trusting anything in it.
- Your application processes the event and works out what it means.
- It updates your data or runs whatever action the event requires, and replies with a success response so the service knows the event arrived.
The main pieces
An event happens — The trigger for everything that follows. Something changes inside another service — a customer pays, a WhatsApp message comes in, someone pushes code to GitHub, an email bounces — and that change is what your application wants to hear about.
External service — The service where the event happened: a payment provider, a messaging platform, a code host, an email provider. It notices the change, describes it as an event, and sends it to the webhook URL you gave it when you set the webhook up. It does not wait for your app to ask.
Webhook request — The webhook itself: an HTTP request — usually a POST — that the service sends to your endpoint the moment the event happens. Its body describes the event, usually as JSON: what happened, when, and an ID. It is a single request, not a connection that stays open, and it usually carries a signature so your server can check where it came from.
Webhook endpoint — A URL your backend exposes specifically for receiving these events, such as /api/webhooks/example. It has to be publicly reachable, so it runs wherever your backend runs, on a server or hosting plan that can execute your code. It receives each request and replies with a success response, but reaching it does not make a request trustworthy.
Verify the request — Do not trust the event only because it reached your URL — anyone can send a request to a public address. Verify it using the method the provider supports, often a signature made with a signing secret you keep on your server. A request that fails the check stops here.
Process the event — Your code reads the verified event and works out what to do: mark an order as paid, update a subscription, add a message to a conversation, record that an email was delivered, start a deployment. Because the same event can occasionally arrive twice, this step should be safe to repeat.
Update your data — Most events change something your application keeps track of: a payment's status, a customer's plan, a conversation, a delivery record. Writing it to your database is what lets every other part of your app act on it later, long after the webhook request is gone.
Run an action — Some events should also set something in motion: send a confirmation email, notify your team, give a customer access, reply to a message, start an automation. It runs on your server, because that is where the event arrived — no one needs to have a browser open.
What is the difference between an API and a webhook?
With an API request, your application starts the conversation. It asks a service for something — create a payment, send a message, fetch some data — and gets an answer back.
With a webhook, the service starts the conversation. Instead of your app asking again and again whether anything has changed, the service sends a request to your app when something does.
The two are usually used together. Your app might call Stripe's API to create a checkout session; later, Stripe sends your server a webhook when the payment succeeds or the subscription changes. A messaging platform works the same way: your app uses its API to send a message, and the platform sends a webhook when a new message arrives.
So a webhook does not replace an API. The API is how your app asks a service for something; the webhook is how the service tells your app that something happened.
Does the browser need to stay open?
No. A webhook normally travels from the service's servers to yours, and no browser is involved at any point.
Once the service knows your endpoint's URL, it can send events whether the person who started things is still on your site, has closed the tab, or was never there at all. That is why anything important, like confirming a payment, belongs in your webhook handler rather than on a success page.
Why verify webhook signatures?
Your webhook endpoint is a public URL, so anyone who discovers it can send it a request — including one that looks exactly like a real event.
Most providers give you a way to prove a request came from them, often a signature created with a secret that only you and the provider know. Each provider does this its own way, so follow its documentation, and keep the signing secret on your server. Only trust the event once that check passes.
What happens if the webhook is sent twice?
If a provider does not get the success response it expects — your server was down, too slow or returned an error — it will usually try again. So the same event can sometimes arrive more than once.
Build your handler to deal with the same event safely more than once (this is called idempotency). A common approach is to record each event's ID and skip any event you have already processed.
Where does a webhook endpoint run?
A webhook endpoint is code that runs on a server, so it needs a place that can run your backend and that the provider can reach over the internet at a public URL.
Static-only hosting just serves files. That is fine for a frontend, but on its own there is no code running to receive a request, verify it and act on it. Some platforms add serverless functions to static hosting, and a function like that can be your endpoint.