A webhook flips the usual direction of an API call. You register a URL with a third party; when an event happens on their side, they POST a JSON payload to your URL. No polling, near-real-time delivery, and a pile of operational details that separate "works in dev" from "survives Black Friday."
POST with a JSON body, sometimes form-encoded for legacy providers.ngrok, cloudflared, localtunnel).The alternative is calling GET /events?since=... every minute forever. That's expensive, rate-limit-prone, and slow to react. Webhooks turn it into push: you find out about a charge, push, build, or message within seconds of it happening.
If you integrate with payments (Stripe, PayPal), source control (GitHub, GitLab), messaging (Slack, Twilio, Discord), CRMs, e-commerce (Shopify), or virtually any SaaS, webhooks are the integration mechanism. Knowing how to consume them well is a backend skill that pays off everywhere.
Anyone on the internet can POST to your webhook URL. Without verification, you'll process forged events. Every reputable provider signs the body — Stripe uses an HMAC-SHA256 in the Stripe-Signature header; GitHub uses X-Hub-Signature-256; Slack uses X-Slack-Signature.
Compute the HMAC over the raw body (not the parsed JSON — whitespace and key order matter), compare with constant-time comparison, reject if it doesn't match. This is the line between "secure integration" and "anyone can mark any order paid."
Most providers time out after a few seconds. Don't do real work in the webhook handler — accept it, persist the raw payload to a queue or DB, return 200 OK, then process asynchronously. Slow handlers cause retries, retries cause duplicates, duplicates cause double-charges.
The same event will arrive twice. Maybe ten times. The provider retried because your handler timed out, or your DB blip returned a 500. Use the event's unique ID (id, event_id, delivery_id) as a deduplication key — record it, refuse to process the same one twice. "Send a refund email twice" is annoying; "charge a card twice" is a phone call.
Webhooks aren't ordered. order.refunded can arrive before order.charged if the network reorders or one retried. Use the event payload's timestamps and resource IDs to reconcile state — when an event arrives, fetch the canonical resource state from the provider's REST API rather than trusting the webhook's snapshot.
Most providers expose a webhook log in their dashboard with delivery success/failure. Wire alerts on:
The best practices for shipping webhooks are the inverse of consuming them:
id on every event so consumers can dedupe.Webhooks are the right answer when one system needs to tell another system that something happened — without making the second system poll. They're the standard for SaaS-to-customer notifications, partner integrations, and async confirmations across organizations.
Inside your own platform, prefer a real message broker (Kafka, RabbitMQ, SNS/SQS) — webhooks add HTTP overhead and rely on every consumer running a public endpoint. Webhooks shine across organizational and trust boundaries; brokers shine inside one.