TL;DR
A webhook is a “reversed” API call: instead of asking the service “did something happen?”, the service sends an HTTP POST to your URL when an event occurs. That avoids polling and saves resources. Ideal for payments, notifications, and sync.
Who this is for
- Developers integrating external APIs (payments, CRM, shops)
- Architects of event-driven systems
- People building automations (e.g. Zapier, n8n, custom backend)
Keyword (SEO)
webhook what is, webhooks api, webhook integration, event callback api
Webhook vs polling
| Polling | Webhook |
|---|---|
| You ask every X seconds: “any new data?” | The service sends a request to you when something happens |
| More requests, latency | Fewer requests, near-instant reaction |
| Simpler on the service side | Requires an endpoint on your side |
Webhook = callback URL you give to the service. On an event (e.g. payment, status change), the service POSTs to that URL with a payload.
When to use webhooks?
- ✅ Payments (Stripe, etc. – “payment confirmed”)
- ✅ Changes in an external system (order, lead, ticket)
- ✅ Notifications (email delivered, SMS sent)
- ✅ Sync (product catalog, prices)
- ❌ When you don’t have a public URL (localhost) – use tunnels in dev (ngrok, cloudflared)
What does it look like on the receiver side?
1. Register URL
In the API dashboard (e.g. Stripe) you provide: https://your-domain.com/api/webhooks/stripe.
2. Receive the request
The service sends a POST with a body (JSON) and often a signature header (e.g. Stripe-Signature).
3. Verification
Always verify the signature (HMAC) so no one can impersonate the service:
// Example: Stripe
const sig = req.headers['stripe-signature'];
const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET);
4. Idempotency
The same event may arrive twice (retry). Use event.id (or similar) and store processed IDs – on duplicate return 200 and do nothing.
5. Respond with 2xx quickly
Return 200 within a few seconds. Do heavy processing in the background (queue, job). The service will retry on timeout or 4xx/5xx.
Best practices
- HTTPS – mandatory
- Signature verification – no exceptions
- Idempotency – handle retries
- Logging – raw body for debugging, no sensitive data in plain text
- Timeout – services usually allow 5–30 s; if longer – return 200 and process asynchronously
FAQ
What if my endpoint is temporarily down?
The service typically retries (e.g. with exponential backoff). After several failures there is often a “failed deliveries” panel or logs on the service side.
Can I use webhooks on localhost?
Not directly. Use a tunnel: ngrok, cloudflared, localtunnel – they expose a public URL to your localhost.
Webhook vs WebSocket?
Webhook = one request per event (stateless). WebSocket = persistent connection, stream of events. Webhooks are simpler for integrating with external providers.