Back to Blog
Fundamentals8 min readApril 21, 2026

How Webhooks Work: From Event to Delivery

Webhooks deliver events via HTTP POST. Here's the complete picture: event triggers, payload format, signature verification, retries, and what to do when things go wrong.

W
WebhookWhisper Team
April 21, 2026

A webhook is an HTTP callback — a POST request that a provider sends to your server when something happens. Understanding the full delivery lifecycle helps you build reliable integrations that handle failures gracefully.

Step 1: You Register a URL

Every webhook starts with registration. You give the provider a URL — your endpoint — and tell it which events to send. Stripe calls this a Webhook Endpoint. GitHub calls it a webhook. Regardless of the name, the mechanism is the same: you're telling the provider 'when X happens, POST to this URL.'

Step 2: An Event Occurs

When the event happens on the provider's side — a payment succeeds, a user signs up, a build completes — the provider constructs a JSON payload describing what happened.

{
  "id": "evt_3PxK2L...",
  "type": "payment_intent.succeeded",
  "created": 1714000000,
  "data": { "object": { "amount": 4999, "currency": "usd", "status": "succeeded" } }
}

Step 3: HTTP POST Delivery

The provider makes an HTTP POST to your URL. Your server must respond with a 2xx status within the provider's timeout window (typically 5-30 seconds). A timeout or non-2xx response is treated as a delivery failure.

Step 4: Signature Verification

Signature verification proves the request came from the provider. The provider signs the raw request body using HMAC-SHA256 with a shared secret. Critical: always verify against the raw bytes of the request body, before any JSON parsing.

import hmac, hashlib

def verify(raw_body: bytes, sig_header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig_header)

Step 5: Respond Fast, Process Async

Return 200 OK immediately. Heavy processing should happen asynchronously after you've acknowledged receipt. This prevents timeouts.

Step 6: Retry Logic

If your server returns a non-2xx response or times out, the provider retries. Stripe retries over 3 days; GitHub retries up to 10 times; Shopify retries 19 times over 48 hours.

Step 7: Idempotency

Because providers retry, your handler may receive the same event more than once. Make your handler idempotent — store event IDs and check before processing.

INSERT INTO processed_events (event_id, processed_at)
VALUES ($1, now())
ON CONFLICT (event_id) DO NOTHING;

Debugging Webhooks

Use WebhookWhisper to capture live webhook traffic with full request details, replay events, and inspect signatures without needing to deploy code.

#webhooks#how-to#http#security

Ready to test your webhooks?

Get a free HTTPS endpoint in under 5 seconds — no signup required.

Create Free Account
How Webhooks Work: A Complete Technical Guide (2026) | WebhookWhisper