- Nothing installed and no account: the test in this guide works with what you already have
- A terminal — how to open one is explained further down
Introduction
A webhook is an automatic notice that a service sends to a web address of yours when something happens. Technically it is an HTTP request — the same mechanism your browser uses to fetch a page — almost always of the POST kind, which is the one used to send data rather than ask for it.
Instead of you asking “did anything change?” over and over (that is called polling), the service tells you when it matters.
In one line: something happens → the service sends a request to your address → your system reacts.
An analogy: polling is calling the bakery every ten minutes to ask whether the bread is ready. A webhook is leaving them your number so they call you when it comes out of the oven.
Problem it solves
Without webhooks, your system would have to ask the service every few minutes whether anything is new. That arrives late and, since many services cap how many questions you may ask per day, it burns that allowance for nothing. With a webhook, whatever produced the event — wherever your code lives (GitHub, GitLab…), your payments provider, your customer database — tells you the moment it happens.
Use it when you want a fast reaction — an automated task that fails, a declined charge, a form submitted — and the source service already knows how to emit these notices. Most large ones do; look for “Webhooks” or “Notifications” in their dashboard.
How it works
- An event happens
- The emitter builds a POST
- Your URL receives JSON
- Your code decides what to do
- You register an address of yours with the emitter to receive the notice (you will see it called a “webhook URL” or “callback URL”).
- When the event fires, the emitter sends a POST with a body — usually in JSON format — plus a few headers.
- Your receiver answers with a 200 code to say “got it”. Codes starting with 2 mean it went well; that is why you see them written as 2xx.
- If your side fails (codes starting with 5, or it takes too long), many emitters retry: you may see the same notice more than once.
Anatomy of a request
| Part | Example | Why it matters |
|---|---|---|
| Method | POST | Deliver the event |
| URL | the one you configured | Destination |
| Header | Content-Type: application/json | How to parse the body |
| Body | { "event": "…" } | Event payload |
Minimal sample body (made up for this guide):
{
"event": "demo.ping",
"source": "guide",
"deliveredAt": "2026-07-16T10:00:00Z"
}Try it now (no server)
The command below POSTs to postman-echo.com (opens in a new tab), a public service that hands back whatever you send it. That shows you the whole gesture without owning a server.
Pick your system in the tabs — the command differs between Windows and everything else.
curl -sS -X POST "https://postman-echo.com/post" \
-H "Content-Type: application/json" \
-H "X-Demo-Event: demo.ping" \
-d "{\"event\":\"demo.ping\",\"source\":\"guide\",\"deliveredAt\":\"2026-07-16T10:00:00Z\"}"In the response, look for the json property (or equivalent): it should match the body. Expected status: 200.
If the public echo fails (timeout or 5xx), open webhook.site (opens in a new tab), copy the unique URL it gives you, and use that instead of https://postman-echo.com/post.
When you wire a real emitter, the URL will be yours (an HTTPS endpoint) or, sometimes, a chat Incoming Webhook URL. Today only the gesture matters: event → POST → someone receives it.
Security (minimum before production)
When you move past the demo:
- Use HTTPS, not
http://. Otherwise the notice travels unencrypted. - If the emitter offers a signature, verify it. Signing means the emitter attaches a code computed with a secret only the two of you share; checking it proves the notice came from them and not from someone who guessed your address. Every provider documents how.
- Emitters retry, so you may receive the same notice twice. If that matters, store each delivery's id and discard repeats.
- Answer quickly with a 200 and do the slow work afterwards (sending the alert, writing to your database). If you take too long to answer, the emitter assumes you failed and retries.
For the HTTP detail: MDN — HTTP (opens in a new tab). For the exact shape of each notice, the emitter's own docs (GitHub, Stripe, etc.).
Common mistakes
| Symptom | Likely cause | What to check |
|---|---|---|
| Emitter retries forever | Your address errored or took too long | Your receiver's log; answer 200 before you start working |
| 404 on the webhook | Bad URL or deleted resource | Fix or regenerate the URL |
| 401 / bad signature | Secret mismatch | Align the secret |
| Chat destination spammed | Incoming Webhook URL leaked | Revoke and create a new URL |
When to use something else
- Polling
- If there are no webhooks or volume is tiny and delay is fine.
- Provider email / native UI
- If you do not need automation yet.
- Queue or event bus
- If you already have internal infra and the SaaS is just another source.
Next step
With the mental model clear, pick a path for what you need:
- A concrete emitter — register your address in its dashboard, verify the signature, and answer 200 (payments, continuous integration, forms…).
- Notify people — from your receiver, call your chat's API or its Incoming Webhook.
- Go deeper — if base HTTP still resists you, MDN (opens in a new tab) explains it from scratch. If you are dealing with charges, the next concept is the signed payment-provider event.
With that, you can wire the pattern in your own stack.
Guided automations
Apply what you learned in this guide with one of our automations: