Dictionary

Webhook

A webhook is an HTTP callback a provider sends to your URL the moment an event happens, so you stop polling for changes. The receiver's job is the hard part: verify the signature, answer with a fast 2xx, and process asynchronously while handling duplicate deliveries.

What is a webhook?

A webhook is an HTTP callback that a provider sends to a URL you own, the moment something happens on their side. A customer pays or a file finishes uploading, and the provider immediately POSTs a small JSON message to your endpoint describing the event. You do not ask for it. It arrives.

With a normal API call, your system asks and the provider answers, so you have to keep asking to learn whether anything changed. A webhook flips that: the provider does the asking and your endpoint answers, which is why people call it a reverse API.

The point is that you stop polling. Instead of hitting an endpoint every few minutes to check for new orders, you register one URL once and let the events come to you.

Webhook versus polling versus a message queue

Three patterns connect systems that need to react to each other. They differ on two things that matter in production: who starts the exchange, and what happens when the receiver is down.

Polling (pull)

Your system initiates. It calls the provider's API on a schedule and asks whether anything is new. This is simple to build and works against any API, but most calls come back empty, you wait up to one interval before you notice a change, and a short interval eats into your rate limit. If your side is down, nothing is lost: you catch up on the next poll.

Webhook (push)

The provider initiates. It sends the event the instant it happens, so there are no wasted calls and almost no delay. The trade is delivery: if your endpoint is down when the event fires, that delivery fails, and you only see the event again if the provider retries. Miss the retry window and the event is gone.

Message queue

A broker sits in the middle. The producer writes a message to the queue and the consumer reads it at its own pace. If the consumer is down, the queue holds the backlog until it recovers, which is the durability a raw webhook does not give you. A common pattern is to accept the webhook and immediately drop it onto a message queue, so a slow or failing worker never costs you an event.

Verifying the signature

Your webhook URL is a public endpoint, so anyone who learns it can POST fake events to it. The provider closes that gap by signing every delivery with a shared secret, and your first job on receipt is to check that signature before you trust a single field.

Stripe is worth spelling out because its scheme is typical. Each request carries a Stripe-Signature header that looks like t=1699999999,v1=5257a869.... You rebuild the signed payload by joining the timestamp, a literal period, and the exact raw request body, then compute an HMAC with SHA-256 using your endpoint signing secret (the whsec_... value) as the key. If your result matches the v1 value, the event is authentic.

Stripe-Signature: t=1699999999, v1=5257a869e7ece...

signed_payload = t + "." + raw_request_body
expected       = HMAC_SHA256(signing_secret, signed_payload)
accept only if  expected == v1  and  now - t < 300 seconds

Two details are easy to get wrong. Sign the raw bytes, not a re-serialised JSON object, because reformatting changes the hash. And check the timestamp: Stripe's libraries reject a delivery whose t is more than five minutes (300 seconds) from now, which stops an attacker from capturing one valid request and replaying it later. GitHub uses the same idea under a different header, X-Hub-Signature-256, and the cross-vendor Standard Webhooks convention names the webhook-id, webhook-timestamp and webhook-signature headers around it. Compare with a constant-time function so the check itself does not leak the secret.

Respond fast, then handle the retries

The provider is waiting on the other end of the connection, and it will not wait long. GitHub expects a 2xx response within ten seconds and treats a slower reply as a failed delivery. Stripe tells you to return a 2xx before any complex logic that could time out. So the receiver pattern is fixed: acknowledge immediately, then do the real work off the request. Write the event to a message queue or a database and return 200 right away, then update the invoice, send the email and sync the CRM in a background worker.

Delivery follows an at-least-once delivery model, so the same event can reach you more than once. If your 200 gets lost on the way back, the provider assumes failure and sends the event again. Stripe retries a failed live delivery with exponential backoff for up to three days. So the same checkout.session.completed can land twice, and a naive handler would create two orders from one payment.

The fix is idempotence: make processing an event twice produce the same result as processing it once. In practice you store the event id the first time you see it and skip it if it comes back, a form of deduplication keyed on that id. This is why webhook consumers and idempotence are almost always discussed together. Order is not guaranteed either, so an updated event can arrive before the created one. Sort on the timestamp inside the payload, not the moment you received it.

Where webhooks show up

Any time one SaaS tool has to nudge another. Shopify sends an order-created event that opens a pick list in your warehouse app or pushes the order into your ERP. You do not need to run a server to catch these. An iPaaS platform gives you a ready-made URL to paste into the provider and lets you build the handling as a visual flow, which is often enough for a small team.

Last Updated: July 10, 2026 Back to Dictionary
Keywords
webhook HTTP callback api idempotence at-least-once delivery deduplication ipaas json HMAC signature event-driven polling integration