Understanding Webhooks
A webhook in web development is a method of augmenting or altering the behavior of a web page or web application with custom callbacks. These callbacks may be maintained, modified, and managed by third-party users and developers who may not necessarily be affiliated with the originating website or application.
Webhooks are automated HTTP “callbacks” triggered by specific events. Instead of constantly polling an API to check if something has changed (polling), an application can provide a URL (a webhook) to receive an immediate HTTP POST request (a push) when the event occurs. They are the backbone of real-time server-to-server communication in modern web applications.
Introduction
Section titled “Introduction”Imagine waiting for a very important package to arrive. You could call the shipping company every 5 minutes to ask, “Is it here yet?” This is annoying, inefficient, and wastes everyone’s time. This is the equivalent of API polling.
Alternatively, the shipping company could ask for your phone number and say, “We will call you the exact moment your package arrives.” This is much better. You provide a contact method (your phone number), and they push the information to you only when necessary. This is precisely how webhooks operate on the web.
The Core Concept
Section titled “The Core Concept”A webhook (sometimes called a reverse API or web callback) allows one system to send real-time data to another system as soon as a given event occurs.
To use a webhook, the receiving application must register a URL (an endpoint) with the sending application. When the target event happens on the sending side, it makes an HTTP request (usually a POST) to that registered URL, carrying a payload (typically JSON) containing information about the event.
Because webhooks represent server-to-server communication, there are always two sides to this transaction.
1. The Receiving Server (Listening for Events)
Section titled “1. The Receiving Server (Listening for Events)”This is the application that wants to be notified. It exposes a public URL and waits for incoming requests.
import { Hono } from 'hono'import { serve } from '@hono/node-server'
const app = new Hono()
// This is our webhook endpoint listening for eventsapp.post('/api/webhooks/github', async c => { const eventAction = c.req.header('x-github-event') const payload = await c.req.json()
if (eventAction === 'push') { console.log( `Received push from ${payload.pusher.name} to repository ${payload.repository.name}`, ) // Trigger build, send slack message, etc. }
// Always respond with a 2xx status code to tell the sender we received it return c.text('Webhook received successfully', 200)})
serve({ fetch: app.fetch, port: 3000 }, info => { console.log(`Webhook server listening on port ${info.port}`)})2. The Sending Server (Triggering the Webhook)
Section titled “2. The Sending Server (Triggering the Webhook)”This is the application where the event actually occurs (e.g., a service like GitHub or Stripe). It actively pushes the data payload to the receiver’s URL.
// The designated URL provided by the receiving applicationconst webhookUrl = 'http://localhost:3000/api/webhooks/github'
const eventPayload = { repository: { name: 'my-learning-curve' }, pusher: { name: 'edouard' },}
async function dispatchWebhook() { try { // The sender makes an HTTP POST request carrying the payload const response = await fetch(webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-github-event': 'push', }, body: JSON.stringify(eventPayload), })
if (!response.ok) { console.error(`Webhook delivery failed: ${response.status}`) } else { console.log('Webhook delivered successfully!') } } catch (error) { console.error('Failed to reach the receiving server:', error) }}
dispatchWebhook()Deep Dive / Advanced Usage
Section titled “Deep Dive / Advanced Usage”While setting up a webhook route is simple in theory, running them reliably in production requires handling several edge cases and security concerns.
Security: Verifying the Sender
Section titled “Security: Verifying the Sender”If your webhook endpoint is exposed to the public internet, anyone could send a POST request to it and pretend to be the legitimate service.
To prevent this, most services use HMAC signatures. The sender signs the payload using a shared secret key and places the signature in a special HTTP header (like X-Hub-Signature). The receiver must compute the signature of the incoming payload using the same secret key and verify that their computed signature matches the one in the header.
Reliability and Retries
Section titled “Reliability and Retries”Because webhooks are sent “fire-and-forget” style by nature, network failures can lead to lost events.
Good webhook providers implement retry logic with exponential backoff if the receiver does not return a 2xx status code.
As a webhook receiver, you should follow these best practices:
- Acknowledge quickly: Respond with a
2xxstatus code as fast as possible to avoid timeouts from the sender. - Process asynchronously: Offload heavy processing (like database writes, email dispatch, or image resizing) to a background queue (e.g., RabbitMQ, Redis…) instead of blocking the webhook HTTP response.
- Ensure idempotency: Since the sender might retry delivering the same event due to a timeout or network glitch, your processing logic must be idempotent. Processing the exact same webhook payload twice should safely result in the same final state without side effects like sending duplicate emails.
Trade-Offs: Webhooks vs. Polling vs. WebSockets vs. SSE vs. Message Brokers
Section titled “Trade-Offs: Webhooks vs. Polling vs. WebSockets vs. SSE vs. Message Brokers”- Polling: Simple to implement but heavily wastes resources on both the client and server. Only appropriate for very low-volume systems or when the data changes infrequently and absolute real-time sync isn’t needed.
- WebSockets: Perfect for continuous two-way communication (like a chat app) and client-server connectivity. Requires maintaining stateful, long-lived connections which can complicate scaling and load balancing.
- Server-Sent Events (SSE): Ideal for one-way (server-to-client) real-time updates over standard HTTP without the full overhead or bidirectional complexity of WebSockets. Good for real-time dashboards or notifications.
- Webhooks: The gold standard for external server-to-server architectural integrations. Efficient as it relies on stateless HTTP requests, but relies heavily on the receiver being highly available, responding quickly, and the network being reliable.
- Queues and Message Brokers: Essential for internal server-to-server async communication or microservices. They solve the availability problem of webhooks by buffering messages until the receiver is ready to process them, ensuring zero data loss and handling massive scale seamlessly.
Conclusion
Section titled “Conclusion”Webhooks are an efficient push-based integration pattern for server-to-server communication. In production, prioritize signature verification, fast acknowledgments, asynchronous processing, and idempotency to keep deliveries secure and reliable.