What Are Webhooks and How Do They Work? A Plain-English Guide
Understand what webhooks are, how they work, and when to use them over polling. A practical introduction for developers and technical founders building integrations.
You are building a product that needs to know when a payment clears, when a new subscriber joins, or when a deploy finishes. You could check every few seconds — but that wastes resources and still introduces lag. Webhooks solve this problem: instead of you asking "has anything changed?", the other system tells you the moment something does.
This guide explains what webhooks are, how they work under the hood, and what you need to build to receive them.
Webhooks in One Sentence
A webhook is an HTTP POST request that an external service sends to your server when a specific event occurs.
That is the whole concept. When Stripe processes a payment, it sends a POST to your server. When GitHub merges a pull request, it sends a POST to your CI system. When Shopify records a new order, it sends a POST to your fulfilment service. You register a URL with the provider, and they call it when relevant events happen.
The alternative — polling — is your server periodically asking the provider "anything new?" Webhooks invert the direction: the provider contacts you.
The Four Steps of a Webhook Delivery
1. You register a URL. In the provider's dashboard or API, you tell them where to send events. This is usually called a webhook endpoint, webhook URL, or callback URL. It must be a publicly reachable HTTPS URL — not localhost.
2. An event occurs. A customer pays. An order ships. A file is uploaded. The provider's system detects this event internally.
3. The provider sends an HTTP POST. The provider constructs a JSON payload describing the event and sends an HTTP POST request to your registered URL. The payload contains details about what happened: the event type, a unique event ID, a timestamp, and the relevant data.
4. Your server responds. Your endpoint processes the event and returns an HTTP 2xx status code to the provider. This tells them delivery was successful. If you return anything else, or if the request times out, the provider assumes delivery failed and will retry.
What a Webhook Payload Looks Like
Payloads vary by provider, but they follow a common pattern. A Stripe payment_intent.succeeded event looks roughly like this:
{
"id": "evt_1Pxabc123",
"type": "payment_intent.succeeded",
"created": 1714000000,
"data": {
"object": {
"id": "pi_1Pxdef456",
"amount": 4900,
"currency": "usd",
"status": "succeeded"
}
}
}Key fields to understand:
id: A unique, stable identifier for this event. It stays the same across retries. Store this for deduplication.type: The event name. Subscribe only to the event types you actually need.created: Unix timestamp of when the event occurred.data.object: The object that changed — the payment, the order, the subscription.
What You Need to Build on Your Side
Receiving webhooks requires three things from you:
A public HTTPS endpoint. Your URL must be reachable from the internet. In development, tools like ngrok or the Stripe CLI can tunnel your localhost to a public URL for testing.
Signature verification. The provider includes a cryptographic signature in the request headers. You verify it against a shared secret to confirm the request came from the provider, not from someone who guessed your URL. Never skip this step.
A 2xx response returned quickly. Return 200 or 202 before doing slow work. If your handler takes too long, the provider's request times out and they retry — which can cause duplicate processing. Accept the event, queue the work, return 200, then process in the background.
Common Misconceptions
"Webhooks guarantee exactly-once delivery." They do not. Providers retry on failures. You will receive duplicates. Design your handler to be idempotent — processing the same event twice should produce the same result as processing it once.
"If I return 200, the data is safely stored." Only if your code actually wrote it. Returning 200 just stops retries. If your downstream database write fails after you returned 200, the event is lost unless you have your own retry mechanism.
"Webhooks are only for payments." They are used everywhere: CI/CD pipelines, CRM updates, shipping notifications, authentication events, content publishing, IoT device state changes, and more.
Next Steps
Once you understand the basics, the important topics to learn are: HMAC signature verification, idempotency patterns, retry and dead-letter strategies, and how to structure your webhook endpoint for testability. Each of these has a substantial body of production knowledge behind it.
If you are building a product integration and want it done correctly from the start — rather than patched after the first production incident — Clixo builds these systems for product teams.