Webhooks & Event-Driven Notifications
How two systems that don't share a database still keep each other informed in real time.
5.6.1Definition
A webhook is a user-defined HTTP callback — an external service sends an HTTP request to a URL a receiving system provides, notifying it that an event occurred (a payment succeeded, a form was submitted). It inverts the usual API request pattern: instead of polling a service repeatedly to check for updates, the service pushes the update the moment it happens.
5.6.2Why It Exists
Polling an external API on a timer to check "did anything change?" wastes requests and introduces delay proportional to the polling interval. Webhooks exist so external systems — payment processors (5.7), email providers (5.8), third-party integrations — can notify a backend the instant something relevant happens, without that backend needing to ask repeatedly.
5.6.3Anatomy of a Reliable Webhook Receiver
- Signature verification — every legitimate webhook provider signs its payload with a shared secret; the receiver must verify this before trusting the request, since the endpoint URL alone is not a secret.
- Idempotency — the same event may be delivered more than once (network retries); handlers must be safe to run twice without duplicating effects.
- Fast acknowledgment — respond 200 immediately and process the event asynchronously (5.10), since providers will retry on timeout.
5.6.4Common Mistakes
- Trusting webhook payloads with no signature verification, allowing anyone who discovers the endpoint URL to forge events — including fake "payment succeeded" notifications.
- Processing the event synchronously inside the request handler, causing the provider to time out and retry, which can trigger duplicate processing.
- No idempotency key handling, so a retried webhook double-charges a customer or sends a duplicate notification.
5.6.5Best Practices
- Always verify the provider's signature before processing any webhook payload.
- Acknowledge receipt immediately, queue the actual processing (5.10).
- Store processed event IDs and skip any event already handled.