Skip to content
general software-development

Webhook

webhook event-driven integration automation
Plain English

A webhook is a “do not call us, we will call you” system. Instead of your application repeatedly asking another service “did anything happen yet?” (polling), you give that service a URL and say “send me a message at this address whenever something happens.” When the event occurs (a payment is made, a commit is pushed, a form is submitted), the service immediately sends the data to your URL. It is how different apps talk to each other in real time.

Technical Definition

A webhook (also called an HTTP callback or reverse API) is a mechanism where a source application sends an HTTP POST request to a pre-configured URL when a specific event occurs. Unlike traditional APIs (where the consumer polls for data), webhooks push data to the consumer in real time.

How it works:

  1. Consumer registers a callback URL with the source service (e.g., https://myapp.com/webhooks/github)
  2. An event occurs in the source (push to repo, payment completed, ticket created)
  3. Source sends an HTTP POST to the registered URL with a JSON payload describing the event
  4. Consumer processes the payload and returns a 2xx status code to acknowledge receipt

Design considerations:

  • Idempotency: the same event may be delivered multiple times (at-least-once delivery). Use event IDs to deduplicate.
  • Signature verification: validate that the request came from the legitimate source using HMAC signatures (e.g., X-Hub-Signature-256 header).
  • Retry logic: if the consumer returns a non-2xx response, the source retries with exponential backoff.
  • Timeout: respond quickly (within 5-30 seconds). Queue long-running work for async processing.
  • Security: validate signatures, use HTTPS, allowlist source IPs if possible.

Webhook vs. polling vs. WebSocket:

PatternDirectionLatencyUse case
PollingConsumer pullsHigh (interval-dependent)Simple, legacy APIs
WebhookSource pushesLow (near-instant)Event notifications
WebSocketBidirectionalLowest (persistent connection)Real-time UI, chat

Receiving and verifying a GitHub webhook

// Express.js webhook handler
import express from "express";
import crypto from "crypto";

const app = express();
app.use(express.json());

const WEBHOOK_SECRET = process.env.GITHUB_WEBHOOK_SECRET;

function verifySignature(req) {
  const signature = req.headers["x-hub-signature-256"];
  const hash = "sha256=" + crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(hash)
  );
}

app.post("/webhooks/github", (req, res) => {
  if (!verifySignature(req)) {
    return res.status(401).send("Invalid signature");
  }

  const event = req.headers["x-github-event"];
  if (event === "push") {
    const { ref, commits } = req.body;
    console.log(`Push to ${ref}: ${commits.length} commits`);
    // Queue deployment, notify Slack, etc.
  }

  res.status(200).send("OK");
});
In the Wild

Webhooks power the integration layer of modern software. GitHub webhooks trigger CI/CD pipelines on every push. Stripe webhooks notify your backend when a payment succeeds or fails. Slack webhooks send messages to channels from external tools. n8n, Zapier, and Make use webhooks as their primary trigger mechanism. In IT infrastructure, monitoring tools fire webhooks to PagerDuty or Opsgenie when alerts trigger. The most common webhook problem is unreliable delivery: if your server is down when the webhook fires, you miss the event. Production implementations use a message queue (Redis, RabbitMQ, SQS) between the webhook receiver and the business logic, ensuring events are processed even if processing fails temporarily.