Skip to content

Webhook Basics: How They Differ from Polling and What the Receiver Must Plan For

Webhook Basics: How They Differ from Polling and What the Receiver Must Plan For

“Notify me when an order comes in.” “Update the status once the payment completes.” Whenever you integrate with an external service, you face the same question: how do you learn that something happened on their side?

There are two broad answers. Ask repeatedly (polling), or be told (webhooks). This article compares them with a small calculation and lays out what the receiving side should think about at design time.

Note: The numbers are a back-of-the-envelope calculation and a minimal experiment with Python’s standard library, not measurements of any particular service. On sender verification, this article sticks to design principles rather than implementation specifics.

What a webhook is

A webhook is a mechanism where when something happens on their side, the other party sends an HTTP request to a URL you registered in advance. It is sometimes called a “reverse API”.

  • Regular API: you ask, they answer
  • Webhook: they notify, you receive

All the receiver needs is one endpoint that external services can call.

Comparing with polling by the numbers

Polling means asking at a fixed interval whether anything changed. Suppose only 3 events happen in a day.

Approach Requests per day Delay before you learn of an event
Polling every 60 s 1,440 (1,437 of them empty) 30 s average, 60 s max
Polling every 5 min 288 (285 of them empty) 150 s average, 300 s max
Webhook 3 Right after the event

Shortening the polling interval reduces delay but increases empty requests. Lengthening it reduces waste but increases delay. It is a genuine trade-off.

Webhooks only communicate when something happens, so they avoid both. The price is that the receiver now gets called from outside, which brings its own design questions.

What the receiver takes on

With polling, you choose when to ask. With webhooks, they call whenever they want. That means accepting several premises:

  1. You must be reachable: if the receiver is down, a notification may be missed
  2. The URL is callable by anyone: it is exposed to the internet, so you need a way to confirm the sender is genuine
  3. The same notification can arrive more than once: most senders retry
  4. Order is not guaranteed: an “updated” event can arrive before “created”

We will go through these in turn.

1. Respond first, work later

Senders generally expect a success status code within a time limit. If your response is slow or an error, they assume delivery failed and retry.

A receiver is easier to run if it works in this order:

  1. Store what you received (enqueue it)
  2. Return a success status immediately
  3. Do the heavy processing afterwards, separately

Doing slow work inline invites timeouts, and timeouts invite retries, which means duplicates.

2. Confirm the sender is genuine

Your endpoint URL is public. You should design from the start for forged notifications that impersonate the sender.

Many services address this with a shared secret: the sender computes a “signature” from the secret and the body, and attaches it to the request. The receiver repeats the calculation and checks for a match.

To get the intuition, we computed signatures over the same body with Python’s standard library:

Comparison Result
Same body, same secret, computed twice Signatures match
One byte added to the body Completely different signature, no match

So even a one-byte change to the body is detectable, and someone without the secret cannot produce a valid signature. That property is the basis for trusting both that a notification is genuine and that it was not altered in transit.

What matters here is less the procedure than the principles:

  • Verify first, before anything else. Trust nothing in the content until verification passes
  • Signature schemes differ by service. Follow that service’s official documentation; do not invent your own check
  • Keep the secret out of source code and public places, and have a way to rotate it if it leaks
  • To guard against replaying old notifications, if the service includes a timestamp, check its freshness too

This article deliberately does not go into verification code or fine-grained checks. When implementing, start from the service’s official documentation and trusted official libraries.

3. Be safe when the same notification arrives twice

Senders retry when they cannot be sure of delivery. That includes cases where you did respond but the response never reached them.

So webhook delivery is usually “at least once”, not “exactly once”. The receiver must assume duplicates. This is where idempotency comes in, covered in What Is Idempotency?:

  • Record the unique ID carried by each notification; if it was already processed, do nothing and return success
  • Prefer updates that specify a state (“set stock to N”) over deltas (“decrement stock”)
  • Record the ID and perform the business change in the same transaction, so you never end up with only one of them done

4. Do not break when order is shuffled

Because of retries and different network paths, notifications do not necessarily arrive in the order events happened. “Shipped” can arrive before “confirmed”.

Two approaches help:

  • If a notification carries a timestamp or sequence number, ignore anything older than the state you already applied
  • Do not rely only on the payload; when needed, fetch the latest state from the other side’s API. Treat the notification as a signal that something happened, and the API as the source of truth

The second is effectively combining polling and webhooks: webhooks for fast awareness, plus low-frequency polling as a reconciliation safety net.

Plan for missed notifications

However carefully you build, receiver downtime or network failures mean some notifications will be missed, and most senders stop retrying after a certain number of attempts or period of time.

Useful safeguards:

  • Log what you receive (body, time received, verification result, processing result), so you can later check whether something arrived
  • Check whether the sender offers redelivery or a delivery history screen
  • Schedule periodic reconciliation against the other side’s API

From a WordPress point of view

On a WordPress site, webhooks typically hit an endpoint provided by a plugin or theme.

  • Heavy handling shares server resources with admin work, so keep receiving light and run the real work separately
  • Check that caching or security plugins are not blocking external POST requests; the cause of “it never arrives” is often in front of the receiver
  • A public endpoint can also be an entry point for attacks, so keep software updated and disable integrations you no longer use

A checklist for your own integrations

  1. Do you return success before heavy work?
  2. Do you verify the sender first, using the official scheme?
  3. Does the result stay the same if the same notification arrives twice?
  4. Does state stay valid if order is shuffled?
  5. Do you have a way to notice and recover missed notifications?
  6. Do you record what you receive?

Summary

  • A webhook lets the other side tell you what happened, avoiding polling’s empty requests and delay trade-off
  • The cost is that the receiver exposes a URL that gets called from outside
  • Five design points: respond first, verify the sender, expect duplicates, expect reordering, plan for misses
  • For signature verification, follow the service’s official scheme; do not build your own check
  • Treat a webhook as a signal, and confirm with the other side’s API when needed

Thinking through what it means to be the one who gets called, before you start building, saves rework later.