Webhooks — Event-Driven Push vs REST API Pull
You have built an integration that checks for new orders every five minutes. It works. But during a busy sale period, you miss an order for four minutes and fifty seconds — and a customer complains. The obvious fix is to poll more frequently. So you drop it to every minute. Now your server is hammering an external API sixty times an hour, mostly getting back nothing useful.
There is a better way. It has existed for years. And the reason most integrations still use polling is not that webhooks are complex — it is that most people never had a clear mental model of the difference.
This post gives you that model. Push vs pull. What each one is actually doing at the HTTP level. When to use each — and what breaks when you pick the wrong one.
🔗 Foundation Posts
This post assumes basic familiarity with REST APIs and HTTP. REST API Design Principles covers the pull model in depth. Event-Driven Architecture explains the broader pattern that webhooks are part of.
The polling problem — why REST alone is not enough
A REST API is pull-based. Your application sends a request, the server responds. You are in control of when data moves. This is exactly right for most interactions — searching, filtering, retrieving a record when a user asks for it.
The problem appears when you need to know the moment something changes. You do not control when that change happens. You have two options: ask repeatedly until something is different, or wait to be told.
Polling is option one. It is simple to implement. It also means most of your requests return nothing new. If an event happens once a day, you spend the other 1,439 polling minutes wasting API rate limits, server resources and bandwidth. The more frequently you poll, the worse those numbers get — and you still miss the gap between requests.
📌 Key Takeaway
Polling trades efficiency for simplicity. It works until the event frequency is low, the volume is high, or the gap between requests starts to matter. That gap is exactly where webhooks come in.
What a webhook actually is
A webhook is an HTTP POST sent by a server to a URL you provide — triggered by an event on their side. That is the whole mechanism.
You register your endpoint URL with the service. You tell it which events you care about — payment.completed, order.shipped, user.created. When one of those events fires, the service sends an HTTP POST to your URL with a JSON payload describing what happened. Your server receives it, processes it, and returns a 200 OK.
That is it. No polling. No repeated requests. No waiting. The data arrives the moment the event happens.
// What a webhook payload looks like (Stripe payment example)
{
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_3N9kJxH...",
"amount": 4999,
"currency": "eur",
"status": "succeeded"
}
}
}
// Your endpoint receives this as an HTTP POST
// You return HTTP 200 to acknowledge receipt
📝 Note
Webhooks are sometimes called reverse APIs or HTTP callbacks. Both names describe the same thing — the direction of the request is reversed. Instead of your system asking a remote server for data, the remote server sends data to your system without being asked.
REST pull vs webhook push — the core difference
The fundamental difference is who initiates the request. With REST, your application initiates every time. With webhooks, the remote system initiates when something happens.
This single difference cascades through everything — efficiency, latency, failure modes, and what your integration looks like at scale.
| Aspect | REST API (Pull) | Webhook (Push) |
|---|---|---|
| Who initiates | Your application — on a schedule or on demand | The remote server — when an event fires |
| When data moves | When you ask for it | The moment the event happens |
| Latency | Up to one full poll interval | Near real-time |
| Wasted requests | Most poll requests return nothing new | Zero — only fires on actual events |
| Your endpoint needed? | No — you call their URL | Yes — you must expose a public URL |
| You control timing? | Yes — completely | No — the remote server decides |
| Handles bulk retrieval? | Yes — filter, paginate, sort | No — one event, one payload |
| Failure handling | You retry the request | Remote server retries the delivery |
| Auth model | You authenticate to their API | They authenticate to your endpoint |
💡 Practical Tip
REST and webhooks are not competitors — they are complementary. The most reliable integration pattern uses both: a webhook fires the moment something happens, then your code calls the REST API to fetch the full record with all the detail it needs. You get real-time triggering without relying on the webhook payload alone.
When to use REST, when to use webhooks
The decision comes down to one question: does your integration need to react to events, or does it need to retrieve data on demand?
| Use REST (pull) when… | Use webhooks (push) when… |
|---|---|
| A user triggers the action — search, browse, submit | An external event should trigger your action — payment, shipment, signup |
| You need to query, filter or paginate data | You need to know the moment something changes |
| You control when the request happens | The remote system controls when something happens |
| You need to retrieve historical data in bulk | You need real-time or near-real-time delivery |
| The remote service does not support webhooks | You are receiving events from Stripe, GitHub, Shopify, Slack, SAP |
| You need complex queries or multi-step workflows | A simple HTTP POST to your endpoint is enough to trigger your logic |
The hybrid pattern — webhooks for triggering, REST for fetching — is how most mature integrations work. A payment webhook tells you a transaction completed. You then call the REST API to get the full invoice, customer record and line items. This separates the real-time signal from the data retrieval, and it makes both parts more reliable.
What can go wrong — the failure modes nobody talks about
Every guide explains how webhooks work when everything is fine. Here is what actually breaks in production.
Your endpoint goes down
When your webhook endpoint is unavailable, the sending service retries — but only up to a limit. Stripe retries for up to 72 hours with exponential backoff. GitHub also retries for up to 72 hours. After that, the event is gone unless you have a separate reconciliation job pulling the REST API to catch up.
Design your endpoint to be stateless and idempotent. If a retry delivers the same event twice, processing it again should not create a duplicate record or double-charge a customer.
⚠️ Warning
Idempotency is not optional. Most webhook providers will retry on any non-200 response — including 5xx errors during processing. If your endpoint processes the event before returning a response, and then crashes, you will receive the same event again on retry. Store a processed event ID and check it before doing any work.
No signature verification
Your webhook endpoint is a public URL. Anyone who discovers it can POST to it with a fabricated payload. Without verification, your system cannot tell a real event from a malicious one.
The standard solution is HMAC-SHA256 signature verification. The sending service signs the payload using a shared secret and includes the signature in a request header. Each provider uses a different header name — GitHub uses X-Hub-Signature-256, Stripe uses Stripe-Signature, Shopify uses X-Shopify-Hmac-Sha256. You compute the expected signature on your side and compare it to the header value. If they do not match, reject the request.
✅ Best Practice
Always verify HMAC-SHA256 signatures before processing any webhook payload. Use constant-time string comparison — not standard equality — to prevent timing attacks. Reject any request without a valid signature with HTTP 401.
Duplicate delivery
Webhook providers guarantee at-least-once delivery, not exactly-once. Network timeouts can cause a retry even when your endpoint processed the event successfully. Build your handler to check whether an event ID has already been processed before taking any action.
No built-in ordering
Webhooks arrive in the order they are delivered, not necessarily in the order the events happened. In high-traffic scenarios, a later event can arrive before an earlier one. If your logic depends on sequence — order created, then payment received, then shipped — you need to handle ordering explicitly in your application, not assume the webhooks will arrive in sequence.
Webhooks in the SAP and enterprise context
The same push-vs-pull principle applies across every SAP integration scenario. The tooling is different but the decision framework is identical.
| SAP Scenario | Integration Approach |
|---|---|
| S/4HANA Cloud business events (purchase order created, invoice posted) | SAP Integration Suite Event Mesh — S/4HANA publishes CloudEvents-format events, Event Mesh delivers them as webhooks to Cloud Integration iFlows or external endpoints |
| Real-time sync from S/4HANA to a third-party system | Webhook-style push via Event Mesh is the recommended pattern — polling via REST is available but creates load on the S/4 OData tier |
| Third-party service notifying SAP of external events (Stripe payment, Shopify order) | Cloud Integration receives the inbound webhook, transforms the payload, and updates SAP via OData or BAPI |
| SAP API Management triggering downstream systems | API Management policies can forward events and calls to external webhook endpoints |
📝 Note
SAP Integration Suite Event Mesh supports webhook delivery for queued events. Your Cloud Integration iFlow URL acts as the webhook endpoint. Event Mesh performs a handshake challenge-response to verify endpoint ownership before activating the subscription — the same security principle as HMAC, applied at the connection setup stage rather than per-payload.
If you are building event-driven integrations on SAP BTP, the SAP Integration Patterns post covers the full integration decision landscape — synchronous vs asynchronous, REST vs events, and where webhooks fit inside the SAP middleware picture.
At a glance — webhooks and REST
| Concept | One-line summary |
|---|---|
| REST API (pull) | Your application asks for data when it needs it — request-response, you control timing |
| Webhook (push) | A remote server POSTs data to your endpoint the moment an event fires |
| Polling | Repeatedly calling a REST API on a timer — works, but wastes requests and adds latency |
| HTTP callback | Another name for a webhook — your URL is the callback that gets hit when something happens |
| Event-driven | Architecture where actions are triggered by events, not by scheduled requests — webhooks are the delivery mechanism |
| HMAC-SHA256 | The standard signature algorithm used to verify that a webhook came from the genuine sender |
| Idempotency | Processing the same event twice produces the same result — essential because webhooks retry on failure |
| At-least-once delivery | What webhook providers guarantee — your handler must be built to handle duplicates |
| Hybrid pattern | Webhook triggers the action, REST API fetches the full detail — the most reliable integration design |
| SAP Event Mesh | SAP’s event broker on BTP — delivers S/4HANA business events as webhooks to Cloud Integration and external endpoints |
What to take away
Most integrations that poll should not poll. The pattern persists because it is familiar and easy to implement — and because the failure is invisible until it matters. Nobody notices a four-minute delay until a customer does.
Webhooks are not complicated. They are an HTTP POST in the opposite direction. The mental model is simple: with REST, you go and collect. With webhooks, it is delivered to your door. The complexity is not in understanding them — it is in handling them properly when they arrive: verifying the signature, returning 200 quickly, handling duplicates, and knowing what to do when your endpoint was down and missed something.
That last point is the one most people skip. Build the happy path, test it, ship it. Then a deployment takes your endpoint offline for three minutes and you never notice the missed events.
The teams whose webhook integrations hold up in production planned for failure from the start — idempotent handlers, event ID deduplication, and a fallback REST reconciliation job for the gaps. Add those three and your webhook integration will be more reliable than the polling it replaces.
🔗 Related posts on this site
Event-Driven Architecture — The Concept Behind Modern Integration — the broader pattern that webhooks are part of: events, brokers, and asynchronous integration.
REST API Design Principles — the pull model in depth: how REST APIs are designed, versioned and secured.
SAP Integration Patterns — The Decisions That Matter — how push, pull and event-driven patterns apply across SAP integration scenarios.
API Security Essentials — HMAC signatures, authentication patterns and how to secure the endpoints your webhooks deliver to.
Published on rakeshnarayan.com — Articles
https://rakeshnarayan.com/articles/webhooks-event-driven-push-vs-rest-api-pull/



Did you enjoy this article?
Let me know — it takes one click.
0 Comments
Leave a Comment
Your comment has been submitted and will appear after review.