skip to content

Why would you use a GitHub webhook instead of polling the GitHub REST API for changes?

level: juniorimportance: should knowfreq 55%

answer

  1. push versus pull
  2. who initiates the HTTP request
  3. state today versus what changed
  4. hourly request quota spent on nothing
  5. X-GitHub-Event and X-GitHub-Delivery headers

basics

~20 s

A GitHub webhook pushes an HTTP POST to your server the moment an event happens, so you learn about it immediately and spend no request quota. Polling burns rate limit, adds latency, and can miss changes that happen between two polls.

solid answer

~50 s

A webhook is a URL you register on a GitHub repository, organization, or GitHub App, together with a list of events. When one of those events occurs, GitHub sends an HTTP POST to that URL with a JSON payload, an `X-GitHub-Event` header naming the event, and an `X-GitHub-Delivery` header holding a unique delivery ID. Polling instead asks the API on a timer: it is slower by up to one poll interval, consumes your hourly primary rate limit on every tick even when nothing changed, and only shows you *state*, not *transitions* — you can see that a label is present now, but not that it was added and removed since your last poll. The tradeoffs are that your receiver must be reachable over the public internet and must be prepared for duplicate and out-of-order deliveries, so most production integrations use webhooks for latency plus a slow reconciliation poll for correctness.

code

text · 10 lines
text
POST /hooks/github HTTP/1.1
Host: ci.example.com
Content-Type: application/json
User-Agent: GitHub-Hookshot/abc1234
X-GitHub-Event: pull_request
X-GitHub-Delivery: 72d3162e-cc78-11e3-81ab-4c9367dc0958
X-GitHub-Hook-ID: 292430182
X-Hub-Signature-256: sha256=d57c68ca6f92289e6987922ff26938930f6e66a2d161ef06abdf1859230aa23c

{"action":"opened","number":42,"pull_request":{"id":1},"repository":{"full_name":"acme/widgets"},"sender":{"login":"octocat"}}

go deeper

for a junior

Be ready to say plainly that GitHub calls you on a webhook while you call GitHub when polling, and that webhooks are faster and cheaper. Naming the X-GitHub-Event header is a good sign.

for a middle

Explain the mechanics: where a webhook is configured, what the delivery headers carry, why a poller burns the hourly rate limit, and why polling shows state rather than transitions.

for a senior

Show the production shape: verify then acknowledge fast, queue the work, deduplicate on the delivery GUID, tolerate reordering, and back the whole thing with a reconciliation sweep for missed events.

for a principal

Own the integration strategy across an org — one shared receiver versus many, how fan-out and replay are handled, and when the operational cost of an always-available public endpoint outweighs the freshness webhooks buy.

## What a GitHub webhook is A webhook is a subscription: you give GitHub a payload URL and tell it which events you care about, and GitHub makes an HTTP POST to that URL whenever one of those events happens. Webhooks can be attached at several scopes — a single repository, an entire organization, a GitHub App (the app has one webhook and receives events from every account that installs it), or an enterprise. The configuration for each is the same handful of fields: the payload URL, the content type (`application/json` or `application/x-www-form-urlencoded`), an optional secret used to sign deliveries, SSL verification, and the event selection (just pushes, everything, or a specific list such as `pull_request`, `issues`, `check_run`). ## What a delivery looks like A delivery is an ordinary HTTP request from GitHub's servers. The headers that matter are: - `X-GitHub-Event` — the event name, for example `push` or `pull_request`. - `X-GitHub-Delivery` — a GUID unique to this delivery, which is what you use to detect duplicates. - `X-GitHub-Hook-ID` — the numeric ID of the webhook that produced it. - `X-Hub-Signature-256` — an HMAC signature over the body, present only when the webhook has a secret configured. - `User-Agent` — begins with `GitHub-Hookshot/`. The body is a JSON object. Most event payloads include an `action` field (`opened`, `closed`, `synchronize`, …), plus `repository` and `sender` objects, and for GitHub Apps an `installation` object identifying which installation the event came from. ## Why polling is the worse default **Latency.** With a one-minute poll you learn about a merge up to a minute late. A webhook arrives in roughly the time it takes GitHub to make one HTTP request. **Rate limit.** Authenticated REST requests draw on an hourly primary quota (5,000 requests per hour for a personal access token at the time of writing; unauthenticated requests get only 60 per hour per IP address). A poller spends that budget on every tick regardless of whether anything changed, and the cost multiplies by the number of repositories you watch. Conditional requests help — sending `If-None-Match` with a previously returned `ETag` and receiving `304 Not Modified` does not count against the primary rate limit — but you still pay in requests that return 200, and you still pay in latency. **State versus transitions.** The API shows you the current state of a resource. If a label was added and removed, or a review was requested and dismissed, between two polls, you will never see it. Webhook events describe the transition itself, which is what most automations actually key on. **Complexity.** A correct poller needs cursors, watermarks, and per-resource change detection. A webhook receiver needs an HTTP endpoint. ## When polling is still correct - Your receiver has no public inbound HTTP — behind a corporate firewall, on a laptop, or in a network where you cannot expose a port. - You need a backfill or reconciliation pass: webhook delivery is best-effort, so a periodic sweep that compares your database against the API catches anything that was dropped while you were down. - The thing you need has no corresponding event. The mature answer in an interview is "both": webhooks for freshness, a low-frequency reconciliation poll for correctness. ## What a receiver must do 1. **Verify the signature** before parsing anything, using the raw request bytes and the shared secret. An unverified endpoint is an open door for anyone who learns the URL. 2. **Respond quickly with a 2xx.** GitHub expects a response within about ten seconds; long processing inside the request handler turns into failed deliveries. 3. **Enqueue and process asynchronously.** Acknowledge, then do the work. 4. **Deduplicate on `X-GitHub-Delivery`.** Delivery is at-least-once in practice, and a delivery can be replayed manually, so handlers should be idempotent. 5. **Do not assume ordering.** Two events fired close together can arrive in either order; where order matters, re-read the current state from the API rather than reconstructing it from the event sequence. ## Common mistakes Treating the payload as trusted input, doing the whole job inline and timing out, assuming exactly-once delivery, and assuming a webhook removes the need for the API entirely — most handlers still call the API to fetch details the payload does not carry.

  • If webhooks are better, why do mature GitHub integrations still poll the API?
    Because webhook delivery is best-effort. If your receiver is down or a delivery fails, that event is gone unless someone redelivers it. A slow reconciliation poll — every few minutes or hours — compares your stored state against the API and repairs drift. Polling is also the only option when the receiver has no public inbound HTTP endpoint.
  • Your handler needs 30 seconds of work per event. What should it do?
    Verify the signature, write the payload to a queue or table, and return 2xx immediately — GitHub expects a response in roughly ten seconds and treats a timeout as a failed delivery. A worker then processes the queued payload. This also makes retries cheap, because the acknowledgement is decoupled from the work.
  • Does a webhook payload usually contain everything you need?
    Often not. Payloads carry the event and the objects directly involved, but many workflows need extra data — the changed files on a pull request, check results, or team membership — which means a follow-up API call. Plan for webhooks to be the trigger and the API to be the source of detail.

Polling is calling the restaurant every five minutes to ask whether your table is ready; a webhook is giving them your phone number and letting them text you.

saying these in an interview costs you the question

  • Claims webhooks guarantee exactly-once, in-order delivery
  • Does all processing inline and returns 2xx at the end
  • Says polling is free because it is read-only
  • Thinks a webhook removes any need to call the API
  • Trusts the payload without verifying the signature

context