Designing and Implementing Webhook Integrations
Define webhook events, subscriptions, and delivery contracts A webhook contract defines which changes a sender reports, where it sends them, and what…
When one service needs to know that data changed in another, it can wait for the provider to send a notification or ask the provider for updates on a schedule. A webhook is an HTTP request, or message sent over the web, that the provider sends to a URL you register when an event you asked it to report occurs. Polling means your service repeatedly calls the provider’s API, its interface for requesting data, to check for changes.
Use webhooks for ongoing updates that should arrive promptly when you can keep a secure URL available to receive requests. Use polling for occasional checks, scheduled reads, or when the provider cannot call your service. When an integration needs prompt notifications and a way to recover missed changes, combine webhooks with API reads or periodically compare your records with the provider’s current data.
With a webhook, the provider sends event data to your endpoint. Your endpoint, the URL that receives the request, verifies that the request came from the provider, saves or queues the event, and responds. A worker can then handle slower tasks, such as updating a database or triggering another service. The GitHub webhook overview describes this event-driven approach as a way to receive updates without repeatedly checking the API.
With polling, your service sends requests at a chosen interval. A short interval finds changes sooner but sends more requests. A longer interval sends fewer requests but leaves changes undiscovered for longer. If your service polls every 60 seconds, for example, a change that occurs just after one check waits nearly a minute for the next one.
The trade-off depends on more than speed. Webhooks require an endpoint that can receive inbound requests, and the provider controls delivery behavior. Polling gives your service control over when it checks, but frequent checks across many resources can consume API quota. GitHub recommends API calls for information needed once or intermittently, or for a small number of resources, while describing webhooks as useful for ongoing event-driven updates.
| Situation | Better starting point | What to check |
|---|---|---|
| You need to react soon after events across many resources | Webhooks | Confirm the provider supports the events you need and document its retry and recovery behavior. |
| You need a one-time read or occasional update | Polling | Use an on-demand API call or a modest schedule rather than maintaining a permanent webhook receiver. |
| Your service cannot receive inbound HTTPS requests | Polling | Confirm your service can reach the provider’s API and that the API supports the required reads. |
| You need prompt updates and a way to recover gaps | Both | Let webhooks trigger prompt work, then read current state or reconcile changes through an API when the provider supports it. |
| You consume messages from a queue | Queue-specific polling | Distinguish queue polling from repeated REST API checks. For Amazon SQS, AWS recommends long polling in most cases because it reduces empty receives. |
A webhook is a strong fit when a provider can notify you about relevant changes and you can keep the receiver available. It avoids many repeated “anything new?” requests when events are sparse. It does not, by itself, establish that every provider delivers every event, delivers them in order, or includes a complete updated record. Check the provider’s event contract and recovery options before relying on notifications as your only record of change.
Polling suits infrequent checks and cases where your service must initiate every request. It also gives you a straightforward way to ask for current state after an outage, provided the API exposes enough history or change-tracking data. The provider’s rate limits, filters, and pagination rules determine how well polling will scale.
For a basic poller that sends one request per monitored resource at a fixed interval:
Requests per day per resource = 86,400 ÷ polling interval in seconds
A 60-second interval produces about 1,440 requests per day per resource. A 5-second interval produces about 17,280. At 1,000 separately polled resources, those schedules produce about 1.44 million and 17.28 million requests per day, respectively.
These are arithmetic examples, not benchmarks. Batching resources into one request can reduce the count, while pagination or retries can increase it. A conditional request can also avoid transferring an unchanged response body. The client sends an entity tag, or ETag, a value that identifies the current version of the response. When nothing has changed, the server can reply with 304 Not Modified. The request still reaches the server, so conditional requests reduce data transfer rather than eliminating polling. See the MDN explanation of conditional requests.
Polling also adds a predictable wait. With a fixed interval of T seconds, a change waits between zero and T seconds for the next check. If changes occur evenly across the interval and requests succeed, the average scheduled wait is about T/2. A 60-second interval therefore implies about 30 seconds of average detection delay, before network and processing time. This is a simple model, not a service guarantee.
Before choosing a frequent schedule, check whether the API lets one request cover several resources (batching), limit which results it returns (filters), mark where to continue through results (cursors), or request changes since an earlier check. These features can let a poller request only relevant changes instead of rereading every record. Their behavior and availability depend on the provider.
A webhook receiver should use HTTPS and verify each delivery with the provider’s documented authentication method. For GitHub, the webhook best practices recommend a secret, SSL verification, and checking the event type and action before processing. Treat the data in the request as input to validate, not as proof that the provider sent it.
Keep the receiver’s work brief. It should validate the request, save or queue the event, and send a response before doing slower work in other services. Response deadlines vary by provider: GitHub recommends a 2XX response within 10 seconds, while Microsoft Graph considers a notification delivered after a 2XX response within 3 seconds. Microsoft Graph also documents retries and possible notification drops under specific conditions, so its delivery rules should not be applied to other providers. Check the Microsoft Graph webhook guidance for its endpoint and delivery requirements.
Design event handling so a repeated delivery does not repeat actions that should happen only once. This is called idempotent processing: handling the same event more than once produces the same intended result as handling it once. Store an event or delivery identifier when the provider supplies one, and use its documented redelivery behavior to avoid handling the same event twice. Also track failed deliveries and whether each notification subscription is active. A provider may require you to renew subscriptions or may offer a separate way to recover missed notifications.
A hybrid design suits integrations that need quick reactions but also need to catch gaps. The webhook tells your service when to act. If the event data does not contain everything your service needs, a follow-up API read provides the current record. A periodic reconciliation can then compare local state with the provider’s state and repair missed updates.
Use this pattern only where the provider’s API supports the necessary reads or change history. Decide what state to store, how to resume after a failure, and how often reconciliation must run based on the freshness and completeness the integration requires. For a small, occasional read, the extra receiver and reconciliation work may not be worthwhile.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com