Skip to content

Web & Backend

Webhooks

A webhook is just an HTTP POST that one service sends to a URL you register, the moment some event happens on its side — a payment succeeding, a pull request opening, a message arriving. There's no special protocol involved: it's a reversal of the usual client-calls-server direction, where the third-party service becomes the client and your server becomes the one receiving the request.

Why it matters

It replaces polling with near-instant notification
Instead of asking a payment provider 'did this succeed yet?' every few seconds, the provider POSTs to your endpoint the moment it knows the answer.
It's how most SaaS integrations actually connect systems
Payment succeeded, a git push happened, a support ticket was updated — webhooks are the standard way these platforms tell your backend something changed.
It decouples systems without a shared database or message broker
Two independently operated services can stay in sync over plain HTTP, with no other infrastructure shared between them.

What a webhook delivery looks like

From the receiving server's point of view, a webhook is indistinguishable from any other incoming HTTP POST: a JSON body describing the event, plus headers that usually include some form of signature so the receiver can verify who really sent it.

http
POST /webhooks/payments HTTP/1.1
Host: yourapp.com
Content-Type: application/json
X-Signature: sha256=7a3f9c1e2b...

{"event": "payment.succeeded", "id": "evt_9F2k", "amount": 4200, "currency": "usd"}

Verifying a delivery is genuine

Because a webhook endpoint is a public URL, anything can POST to it — including an attacker who has guessed or found the URL. Providers address this by signing each payload with a shared secret (commonly HMAC) and sending the signature in a header; the receiver recomputes it and rejects the request if it doesn't match, rather than trusting the payload just because it arrived on the expected path.

Retries, ordering, and idempotent handling

Most providers retry a delivery if your endpoint doesn't respond quickly with a success status, which means the same event can arrive more than once. A handler needs to record which event IDs it has already processed and treat a repeat as a no-op, and should do any slow work (sending emails, calling other services) asynchronously after acknowledging receipt, rather than making the provider wait on it.

Mistakes people make here

Not verifying the signature on incoming webhooks
Without it, anyone who discovers or guesses the endpoint URL can POST a fabricated event — a fake 'payment succeeded' notification, for instance — and the receiving server has no way to tell it apart from a genuine one.
Doing slow, synchronous work inside the webhook handler
If the handler takes too long, the sender's request times out, which usually triggers a retry — so the same event gets processed twice (or more), and the underlying slow work never actually gets a chance to succeed within the provider's timeout.
Assuming delivery happens exactly once, in order
Most providers guarantee at-least-once delivery, not exactly-once, and don't promise ordering — a handler that isn't written to be idempotent and order-tolerant will eventually process a duplicate or an out-of-sequence event incorrectly.
Not planning for local development
A webhook needs a publicly reachable URL, which a developer's own machine isn't by default; testing usually requires a tunneling tool or a staging environment set up to receive real deliveries.

Strengths and trade-offs

Where it is strong

  • No polling overhead — the receiving side does nothing until there's actually something to know.
  • Near-real-time notification with none of the persistent-connection machinery a WebSocket needs.
  • Simple to implement on the receiving end: it's just an HTTP endpoint, nothing provider-specific to install.
  • Decouples two systems without requiring a shared database, message broker, or ongoing connection.

The trade-offs

  • The receiving endpoint has to be publicly reachable, which complicates local development and requires a tunneling tool or a deployed environment to test against.
  • Delivery isn't guaranteed exactly-once or strictly ordered by most providers, so the receiver has to handle duplicates and out-of-order arrival itself.
  • You're dependent on the sender's retry behavior and timeout window, which varies by provider and isn't something you control.
  • Debugging is harder than a normal request/response call, since you don't control when deliveries arrive and often have to rely on the provider's own delivery logs to replay one.

Who needs this

Relevant to anyone integrating with a third-party platform — payments, git hosting, chat, CRM — where that platform needs to notify your backend about events.

Questions about webhooks

How is a webhook different from a regular API call?
The direction is reversed. With a normal API call, your application is the client asking a service for data. With a webhook, the service is the client, and your application's endpoint is the one receiving the request, unprompted, when an event happens.
How do I test webhooks on my local machine?
Since your laptop isn't normally reachable from the internet, most developers use a tunneling tool that exposes a local port through a public URL temporarily, or rely on a provider's webhook-replay feature against a deployed staging environment.
Are webhooks secure by default?
No — an endpoint that accepts a POST from anywhere has to verify the request is genuinely from the expected sender, typically by checking a signature the provider includes in the request headers, rather than trusting the payload just because it arrived.
What happens if my server is down when a webhook fires?
It depends entirely on the sending provider's retry policy — most retry with some backoff for a period of time, but a provider that doesn't retry, or a server that's down longer than the retry window, means that event is simply lost unless you have another way to reconcile state.

The primary source

Related concepts

← All concept guides