Webhook vs API: push vs pull, polling cost and when to use each
A webhook pushes data to your URL when an event happens; an API waits for your code to ask. Polling one resource every 60 seconds costs 1,440 requests a day, while GitHub allows 60 unauthenticated requests an hour, so most apps use webhooks for events and the API for reads.
A webhook pushes data to your URL when an event happens, while an API waits for your code to ask, so the real difference is who starts the request. Both are plain HTTP, and Twilio's docs describe it well: the REST API handles requests from your app to Twilio, and webhooks handle the reverse. Below is a side-by-side table, what polling really costs, when each one wins, and the pattern most production apps use, which is both together.
Push vs pull: who starts the request
Say you want to know when a GitHub issue is opened. With pull, your code calls the GitHub REST API on a timer and compares the results, and most calls return nothing new. With push, you register a webhook once and GitHub sends a POST with the issue in the JSON body when it happens.
GitHub's docs note that webhooks take less effort and fewer resources than polling, scale better, and allow near real-time updates. A webhook endpoint is just an API endpoint that you host and the provider calls, which is why webhook vs API is about direction, not a different technology.
Webhook vs API side by side
Here's how the two compare on who starts the request, delay, cost, reliability and security.
One point the table can't show: a webhook tells you that something changed, often with a snapshot of the object at that moment, while an API call tells you the state right now.
| Webhook (push) | API polling (pull) | |
|---|---|---|
| Who starts the request | The provider, when an event happens | Your code, on a timer or on demand |
| Delay | Near real time | Up to one polling interval, for example 60 seconds |
| Requests when nothing changes | None | Every poll still counts: 1,440 a day at 60 seconds |
| Rate limits | You make no calls, so no quota is used | Each poll counts: GitHub allows 60 an hour without a token, 5,000 with one |
| Reliability | Provider retries on failure (Stripe up to 3 days, GitHub not at all); duplicates and out-of-order events happen | You control retries; a failed poll is caught by the next one |
| Security | You run a public HTTPS endpoint and verify a signature | Outbound calls with your API key; nothing public to protect |
| Best for | Reacting to events: payments, pushes, orders | Reading data on demand, backfills, one-off lookups |
What polling really costs
A day has 86,400 seconds, so polling one resource costs 86,400 divided by the interval in requests per day, per resource, whether anything changed or not.
GitHub allows 60 requests an hour without a token, so polling one repository once a minute uses the whole hourly budget. A personal access token gets 5,000 an hour, and the GITHUB_TOKEN in GitHub Actions gets 1,000 an hour per repository.
GitHub's own advice is to avoid polling and subscribe to webhook events. If you must poll, respect the x-poll-interval header and use authenticated conditional requests (etag or last-modified), because a 304 Not Modified answer doesn't count against your primary rate limit.
| Polling interval | Requests per hour | Requests per day |
|---|---|---|
| Every 5 seconds | 720 | 17,280 |
| Every 10 seconds | 360 | 8,640 |
| Every 60 seconds | 60 | 1,440 |
| Every 5 minutes | 12 | 288 |
| Webhook | Only when an event happens | Only when an event happens |
When to use an API call, and when a webhook
Call the API when:
- You need data once or on demand, like when a user opens a page.
- You need the current state rather than a change.
- You're backfilling history.
- The provider has no webhook for that data.
- You can't run a public HTTPS endpoint.
Use a webhook when:
- You must react within seconds to a payment, a push, or an order.
- You watch many resources and polling would burn your rate limit.
- Changes are rare, so polls would mostly come back empty.
GitHub's rule of thumb is simple: call the API if you only need information once or intermittently, or from a small set of resources with no plans to scale up.
Use both: the webhook as a trigger, the API as the truth
In most production integrations, the webhook tells you something changed, and then you call the API for the full, current object. Stripe built this into thin events: it sends a lightweight notification with the event type and resource ID, and your code fetches the latest state from the API. Shopify tells apps not to rely on webhooks alone and to run reconciliation jobs that periodically fetch data.
Check the event ID on arrival, because Stripe doesn't guarantee event order and can send the same event more than once. Run a periodic sync too for anything you missed while your endpoint was down, since GitHub doesn't automatically redeliver failed deliveries (more in the webhook retries guide).
See the push side for yourself
To see the push side live, create a free bin on webhooks.sh, paste its ingest URL into a provider's webhook settings (GitHub, Stripe, or Shopify), trigger an event, and compare the JSON that gets pushed with what the API returns for the same object. Or play the provider yourself with the curl commands below.
A free bin lasts 48 hours, takes 100 requests a day and bodies up to 100KB, shows the latest 10 requests in the viewer, and always answers 200 with its own small JSON ({"ok":true,"delivery_id":"..."}), so it shows what arrives but doesn't run your logic. Claim it with a free Google sign-in to keep the URL past 48 hours.
# 1. Create a free bin (or open view.webhooks.page)
curl -X POST https://webhooks.sh/v1/bins
# 2. Push an event to it, the way a provider would
curl -X POST https://<bin>.webhooks.page/events \
-H "Content-Type: application/json" \
-d '{"type":"order.created","id":"ord_123"}'
FAQ
Is a webhook an API?
A webhook is an HTTP request the provider sends to an endpoint you host, so it uses the same building blocks as an API, just in the other direction. Twilio describes webhooks as requests from Twilio to your app responding to events it processes.
Do webhooks count against API rate limits?
No, receiving a webhook isn't an API call from your side, so it uses none of your quota. GitHub recommends subscribing to webhooks instead of polling to stay within its API rate limit.
What is the difference between a webhook and a REST API?
When people compare a webhook vs REST API, the difference is who initiates the call. With a REST API, your code sends requests to the provider's URLs; with a webhook, the provider sends requests to yours when something happens.
Can I use webhooks and an API together?
Yes, and most apps do: the webhook acts as the trigger, and the API returns the current state. Stripe thin events and Shopify reconciliation jobs both work this way.
Are webhooks less secure than APIs?
Webhooks need a public HTTPS endpoint, so you should verify the signature header (like Stripe-Signature, X-Hub-Signature-256, or X-Twilio-Signature) on every request and reject anything that fails. Polling only makes outbound calls using your key.
How can I see what a webhook sends before building anything?
Point the sender at a free webhooks.sh bin and read each request live in your browser. It needs no signup, lasts 48 hours, and takes up to 100 requests a day.
Last updated
Try it in 10 seconds.
Create a free bin at view.webhooks.page — no signup, no install. Point your sender at the URL and watch requests land live. Bins expire after 48 hours.