Webhooks and polling both move changes from one system into another, but the difference is who starts the conversation. With a webhook, the provider sends an HTTP request when an event happens. With polling, your application asks the provider for changes on a schedule. Webhooks can reduce delay and unnecessary requests. Polling gives the consumer tighter control over timing and recovery. Neither method is automatically reliable.
The practical choice depends on event volume, acceptable delay, provider behavior and how much failure handling you are prepared to operate.
The difference in one table
| Question | Webhook | Polling |
|---|---|---|
| Who starts the request? | The provider | Your application |
| Typical delay | Seconds, if delivery works | Up to the polling interval |
| Requests when nothing changed | Usually none | One per interval |
| Inbound public endpoint needed | Usually yes | No |
| Recovery model | Provider retries, delivery log or your reconciliation job | Repeat the next request from a stored cursor or timestamp |
| Common failure | An event is missed, duplicated or processed out of order | Requests waste quota, overlap or skip changes at a boundary |
| Best fit | Event-driven updates with a dependable sender | Controlled synchronization, reconciliation and providers without webhooks |
That table hides an important point: webhooks and polling solve delivery, not correctness. Your application still needs to decide whether an event is new, whether it arrived in the right order and whether the underlying resource has changed again since the event was created.
What a webhook actually guarantees
A webhook is an outbound HTTP request from a provider to a URL you register. Stripe, for example, sends event data to an HTTPS endpoint. GitHub sends a delivery with headers identifying the event and delivery.
The request is not the same as a durable message sitting in your database. A network timeout can occur after your server stores the event but before the provider sees the response. The provider may then send the same event again. A provider can also stop retrying after a documented window.
Delivery behavior is provider-specific:
- Stripe says live-mode events are retried for up to three days with exponential backoff.
- GitHub says failed webhook deliveries are not redelivered automatically. You must redeliver them manually or build a scheduled recovery process.
- GitHub expects a
2xxresponse within 10 seconds. Stripe also tells endpoints to return2xxbefore doing complex work.
So “use webhooks” is not a complete reliability plan. Read the sender’s retry rules, retention window and redelivery tools before relying on the stream.
A safe webhook receiver
A robust receiver does as little work as possible on the request path:
- Read the raw request body.
- Verify the provider’s signature or secret according to its documentation.
- Check the event or delivery ID against a unique constraint.
- Store the payload or place a reference on a durable queue.
- Return
2xxquickly. - Process the business action in a worker.
The unique constraint matters because duplicate delivery is normal, not exceptional. Stripe tells integrations to track event IDs. GitHub recommends using the X-GitHub-Delivery header and notes that a redelivery keeps the original value.
Do not make a slow downstream call before acknowledging the event. If that call takes too long, the sender can mark the attempt as failed even though your process eventually succeeds. The retry then arrives beside the first attempt.
Signature verification also has implementation details. Stripe requires the unmodified raw body. Parsing and re-serializing JSON before verification can change the bytes and break the signature check. Treat the provider’s current documentation as the source of truth for the exact verification algorithm.
What polling actually guarantees
Polling is a repeated read. Your application asks for records changed after a stored cursor, sequence number or timestamp. It processes the response, stores progress and asks again later.
That can be easier to reason about because your application controls the schedule and can retry the same query. It can also be expensive or imprecise if the API offers only a full-list endpoint.
A useful polling API provides at least one of these:
- a stable cursor that can resume after the last processed item;
- an increasing sequence number;
- a
modified_sincefilter with a clearly documented time format and ordering rule; - an
ETagorLast-Modifiedvalidator for conditional requests.
HTTP conditional requests can reduce response bodies when a resource has not changed. A client sends If-None-Match with the last ETag, and the server can return 304 Not Modified instead of the representation. That saves transfer, but it still consumes a request and can still count against the provider’s rate limit.
If the API returns 429 Too Many Requests, follow its documented limit and Retry-After behavior rather than immediately repeating the call. Our guide to API rate-limit retries explains the backoff problem in more detail.
Polling has boundary bugs
Time-based polling looks simple until two records share a timestamp or the provider’s clock differs from yours.
Suppose the last successful run stored 2026-10-14T08:00:00Z. If the next query asks for records strictly after that instant, a record committed later but stamped at exactly 08:00 can be missed. If the query asks for records at or after the instant, the boundary record returns again.
The safer choice is usually to accept overlap and deduplicate by a stable record ID. Keep a small look-back window, sort using the provider’s documented order, and advance the checkpoint only after every item in the page is durably processed.
Do not use your job’s start time as the checkpoint unless the API explicitly supports that model. Pagination can run for minutes, and changes can occur while the pages are being read.
When webhooks fail
Webhooks are a good fit when:
- the provider has a documented retry or redelivery system;
- changes should reach your application within seconds;
- events are infrequent enough that polling would mostly return nothing;
- you can expose and monitor an HTTPS endpoint;
- you can deduplicate, queue and reconcile deliveries.
They become awkward when inbound networking is restricted, the sender offers weak delivery history or one endpoint receives bursts too large for its workers. A queue absorbs the burst, but it does not replace capacity planning.
Provider outages are another limit. If the sender cannot create or deliver events, your endpoint cannot fix that. A cloud-region outage can affect the producer, your receiver or both.
When polling fails
Polling is a good fit when:
- a few minutes of delay is acceptable;
- the provider offers stable cursors or change filters;
- you need a regular full reconciliation anyway;
- inbound webhooks are unavailable or difficult to secure;
- your application must control when load occurs.
It becomes expensive when many consumers ask frequently and most responses contain no changes. It also creates a hard tradeoff: shorter intervals reduce delay but increase request volume; longer intervals save quota but increase staleness.
Avoid overlapping pollers. Use a lease or single-flight lock so a slow run does not continue after the next scheduled run starts. If parallel workers are required, partition work by a stable key rather than letting every worker scan the same feed.
The hybrid design is often better
Many production integrations use both methods.
The webhook is the fast path. It tells the application that something changed and places work on a queue. The worker then fetches the current resource from the provider instead of assuming the event snapshot is still current.
Polling is the repair path. A scheduled reconciliation asks for changes since the last checkpoint and recovers anything missed during an outage, expired retry window or configuration mistake.
This design treats the webhook as a notification, not the only ledger. It also gives you a controlled way to rebuild state after a bug.
A practical hybrid loop is:
- accept and verify webhook deliveries;
- deduplicate by event ID;
- queue the affected resource ID;
- fetch the current resource and apply an idempotent update;
- run a periodic cursor-based reconciliation;
- alert when the webhook stream is quiet while reconciliation still finds changes.
That last metric catches silent failures. A green endpoint health check does not prove that the provider is still sending the events you expect.
How to choose
Choose webhooks as the primary path when low latency matters and the provider documents delivery, retries and redelivery. Choose polling as the primary path when the API provides a reliable cursor and your acceptable delay is longer than the polling interval.
Use both when missed changes have a real cost. The webhook reduces latency. The poller proves completeness.
Whichever design you use, test the failure cases: duplicate delivery, out-of-order events, a 20-minute endpoint outage, a stuck worker, a rate-limit response and a crash after data is written but before the checkpoint advances. Those tests reveal more than a happy-path demo.
Questions
Is a webhook faster than polling?
Usually. A webhook can arrive seconds after an event. Polling cannot normally detect a change before the next interval. Network delays, queues and provider outages can still delay a webhook.
Can a webhook be delivered twice?
Yes. A provider can retry after a timeout even if the first attempt reached your application. Store a stable event or delivery ID with a unique constraint and make processing idempotent.
Does polling miss changes?
It can if the cursor or timestamp boundary is handled incorrectly. Prefer provider-issued cursors. With timestamps, use overlap and deduplicate rather than assuming every timestamp is unique.
Should a webhook replace reconciliation?
Not when completeness matters. A scheduled reconciliation can recover events missed during downtime, an expired retry window or a configuration error.
Do conditional requests remove polling costs?
No. ETag and If-None-Match can avoid transferring an unchanged response body, but the request still occurs and may count against rate limits.
Sources
Checked October 14, 2026:





