Go REST

What is a webhook?

Webhooks vs polling: the inverse of an API call, when to use them, and how the receiving endpoint should look.

A webhook is an HTTP endpoint that another service calls when something happens. It is the inverse of a normal API call: instead of you asking the upstream "did anything change?", the upstream tells you the moment it does.

The mental model: a regular API call is a phone call you place. A webhook is a phone number you publish, and the upstream calls you. You give them a URL on your server, they POST a JSON body to it whenever a relevant event happens, and your server reacts.

Why webhooks exist

The alternative is polling: every minute, you callGET /payments?status=succeeded and look for new rows. Polling works, but it has three downsides:

Webhooks fix all three. The upstream sends one HTTP call per real event. You learn within milliseconds. No polling traffic.

What a webhook payload looks like

When the event fires, the upstream sends an HTTP POST to the URL you registered. The body is JSON describing what happened:

POST /webhooks/payment-succeeded HTTP/1.1
Host: yourapp.example.com
Content-Type: application/json
X-Signature: sha256=abc...123

{
  "id": "evt_5g7H4Z",
  "type": "payment.succeeded",
  "occurred_at": "2025-09-01T12:34:56Z",
  "data": { "amount": 4900, "currency": "INR" }
}

Three things you should expect in every webhook:

Receiving a webhook

Your endpoint is just a regular POST handler. The two important rules:

app.post("/webhooks/payment-succeeded", express.json(), (req, res) => {
  // 1. Verify the signature first
  const signature = req.headers["x-signature"];
  if (!verifyHmac(req.body, signature, SECRET)) {
    return res.status(401).end();
  }

  // 2. Acknowledge fast, then do real work async
  enqueueJob("payment-succeeded", req.body);
  res.status(200).end();
});

Idempotency

Webhook providers retry. A network blip, your server returning 500, a slow ack: any of these triggers a retry. Your handler can receive the same event id twice. Dedupe by event id at the database level: insert a row keyed onevent_id, and on duplicate-key error, do nothing and ack.

Replay attacks

An attacker who captures one webhook payload can replay it. Two defences:

Stripe's webhook signing scheme (Stripe-Signature) does both. Mirror the pattern when you publish your own.

Local development

Webhook URLs need to be reachable from the public internet. During development, run a tunnel:

Most webhook providers also have a "test" / "send sample" button in their dashboard; use it to develop your handler before subscribing to real events.

Webhooks vs server-sent events vs WebSockets

Three patterns for "the server pushes to the client":

If you are integrating two backend services, webhooks are almost always the right answer. If you are pushing data to a browser tab, use SSE or WebSockets.

Does Go REST have webhooks?

Not currently. Go REST is a synchronous fake-data API for testing client code. Webhooks would mean every project gets an event firehose, which is not the use case. If you want to test how your code receives webhooks, use a tool likerequestbin.com or build a small endpoint and trigger events from your own backend.

Continue reading

More primers

All primers Glossary Integration guides