In short
Asking a payment API 'paid yet?' every five seconds wastes everyone's time. With a webhook, the payment provider calls your server the moment the money arrives.
A way for your server to notify another system in real time by sending an HTTP request when an event happens — the inverse of a normal API call, where the 'server' becomes the caller.

Think of it like this
The delivery guy rings the bell
You don't stand at the gate every two minutes waiting for a parcel. You sit with your chai, and the delivery person rings the bell when he arrives. A webhook is that bell: you share a URL, and the other service calls it when something happens.
Watch it happen
A payment succeeds
POST /webhooks/payments
1/5A payment succeeds. The provider sends the event to the URL you registered.
The big ideas
What you need to know
They call you
You expose an HTTPS endpoint. The other service POSTs JSON to it whenever an event happens.
Always verify the signature
Anyone can POST to your URL. Check the provider's HMAC signature before trusting the body.
Expect duplicates
Providers retry on failure, so one event can arrive twice. Store event ids and ignore repeats.
Answer fast
Return a 2xx within a few seconds and push slow work to a queue, or the provider marks the delivery failed.
See it in code
Walk through the code
1import crypto from "node:crypto";2 3app.post("/webhooks/payments", express.raw({ type: "application/json" }), (req, res) => {4 const expected = crypto5 .createHmac("sha256", process.env.WEBHOOK_SECRET!)6 .update(req.body)7 .digest("hex");8 const got = String(req.header("x-signature") ?? "");9 10 if (got.length !== expected.length ||11 !crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))) {12 return res.sendStatus(401);13 }14 queue.add("payment-event", JSON.parse(req.body.toString()));15 res.sendStatus(200);16});1/4express.raw keeps the exact bytes. Signatures are computed on the raw body, not on parsed JSON.
The header name and format differ by provider, so check their docs. queue is any job queue, like BullMQ.
Save yourself the pain
Common mistakes
Oops
Processing a webhook without checking its signature.
Do this instead
Anyone who finds the URL could fake a 'payment succeeded'. Verify the signature and reject on mismatch.
Oops
Doing slow work like sending emails before replying.
Do this instead
The provider may time out and retry, causing duplicates. Acknowledge fast, then process in a background job.
Your mission
Catch a real webhook
Quick check
Why should a webhook handler remember the event ids it has processed?
Go deeper
- 1Build an endpoint that receives a webhook from a third-party service (e.g. Stripe, GitHub).
- 2Verify webhook authenticity using a signature header, not just trusting the payload.
- 3Design your own webhook system that notifies external URLs when an event occurs in your app.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.