
Webhooks
Webhooks look simple because they are just outbound HTTP POSTs. In production they are a delivery system with retries, signatures, dead-letter handling, backoff, and consumer support issues. If the sender cannot answer whether an event was delivered, retried, duplicated, or dropped, the integration will eventually fail under load or ambiguity.
Minimal Example
const payload = JSON.stringify(event);
const signature = createHmac("sha256", secret)
.update(payload)
.digest("hex");
await fetch(endpoint, {
method: "POST",
headers: {
"content-type": "application/json",
"x-signature": signature,
},
body: payload,
}); What It Solves
- Pushes state changes to consumers without requiring them to poll continuously.
- Decouples your internal event timing from the consumer’s processing model.
- Lets external systems integrate on a standard transport they already know how to receive.
Failure Modes
- Sending unsigned payloads and assuming the receiver knows the request is genuine.
- Retrying forever without idempotency keys or delivery state, creating duplicate side effects.
- Hiding event schema changes until downstream consumers break in production.
Production Checklist
- Sign payloads, timestamp them, and document verification exactly.
- Store delivery attempts with status, next retry time, and terminal failure reason.
- Publish idempotent event IDs so receivers can de-duplicate safely.
Closing
Treat webhooks as a product and a queue, not as a helper function. The HTTP call is the smallest part of the problem.









