Learn

What is a Webhook? Developer Guide with Examples

A practical guide to webhooks for developers: how they work, how they compare to polling, security best practices using HMAC signatures, common implementation patterns, and real-world examples in notification systems.

Definition: What is a Webhook?

A webhook is an HTTP callback -- an HTTP POST request that one application automatically sends to another application when a specific event occurs. Instead of your application repeatedly asking "Did anything happen?" (polling), the source application proactively tells you "Something happened" by sending data to a URL you provide. Webhooks are sometimes called "reverse APIs" because the data flow is inverted: instead of you calling an API to get information, the API calls you.

In everyday terms: Polling is like repeatedly checking your mailbox every five minutes. A webhook is like having the mail carrier ring your doorbell when a package arrives. Webhooks are event-driven -- they only fire when something actually happens, and they deliver the data immediately.

Webhooks are foundational to modern web architecture. They power everything from payment processing (Stripe sends a webhook when a payment succeeds) to version control (GitHub sends a webhook when code is pushed) to notification delivery (notification APIs send webhooks when a message is delivered or bounced). If you have built any application that integrates with external services, you have almost certainly consumed or produced webhooks.

How Webhooks Work

The webhook lifecycle involves three parties: the event source (the application where the event happens), the webhook (the HTTP request itself), and the webhook receiver (your application that processes the event). Here is how they interact.

You Register a Webhook URL

You tell the source application where to send event data by providing a publicly accessible URL (the webhook endpoint). This is typically configured through the source application's dashboard or API. For example, you might register https://yourapp.com/webhooks/stripe in Stripe's dashboard to receive payment events.

An Event Occurs

Something happens in the source application that matches the events you subscribed to. A payment succeeds, a message is delivered, a repository receives a push, a form is submitted. The source application detects this event and prepares a webhook payload.

The Source Sends an HTTP POST

The source application sends an HTTP POST request to your registered URL. The request body contains a JSON payload with details about the event -- what happened, when it happened, and any relevant data. The request typically includes security headers (like an HMAC signature) so your receiver can verify that the request genuinely came from the source application.

Your Application Processes the Event

Your webhook endpoint receives the POST request, verifies the signature, parses the payload, and takes whatever action is appropriate. This might mean updating a database record, triggering a downstream notification, sending a confirmation email, or logging the event. Your endpoint responds with an HTTP 200 status to acknowledge receipt.

Here is what a typical webhook payload looks like in practice:

// Example: Webhook payload from a notification delivery service
// POST https://yourapp.com/webhooks/notifications

{
  "event": "message.delivered",
  "timestamp": "2025-01-20T14:32:07Z",
  "data": {
    "message_id": "msg_abc123",
    "channel": "telegram",
    "recipient": "[email protected]",
    "status": "delivered",
    "delivered_at": "2025-01-20T14:32:06Z"
  }
}

Webhooks vs. Polling: When to Use Each

Webhooks and polling solve the same fundamental problem -- how to know when something changes in an external system -- but they do it in opposite ways. Understanding the tradeoffs helps you choose the right approach for each situation.

Characteristic Webhooks Polling
Data flow Push: source sends data to you Pull: you request data from source
Latency Near real-time (seconds) Depends on polling interval
Efficiency Only fires when events occur Wastes requests when nothing changed
Infrastructure Requires a publicly accessible endpoint Works behind firewalls, no public URL needed
Reliability Can miss events if your server is down Catches up naturally on next poll
Complexity Must handle retries, deduplication, ordering Simpler to implement correctly
Scalability Scales with event volume, not time Scales with number of resources to check

Use webhooks when you need real-time or near-real-time awareness of events, when the event frequency is unpredictable, or when the source application supports them. Payment processing, notification delivery status, CI/CD pipelines, and messaging platform events are all natural webhook use cases.

Use polling when you cannot expose a public endpoint (internal networks, firewalled environments), when the source does not support webhooks, when you need guaranteed completeness (webhooks can be missed during downtime), or when the data changes at a predictable, low frequency. Some teams use both -- webhooks for real-time awareness and periodic polling as a safety net to catch any missed events.

Common Webhook Use Cases

Webhooks appear across virtually every category of web service. Here are the most common use cases developers encounter.

Payment Processing

Stripe, PayPal, and other payment providers send webhooks for successful charges, failed payments, subscription changes, refunds, and disputes. Essential for keeping your database in sync with payment state.

Notification Delivery Status

Notification APIs send webhooks when messages are delivered, bounced, opened, or clicked. Allows your application to track transactional notification delivery in real time.

Version Control Events

GitHub, GitLab, and Bitbucket send webhooks for pushes, pull requests, issues, reviews, and releases. Powers CI/CD pipelines, deployment automation, and team notifications.

Form Submissions

Form services like Typeform, Jotform, and Google Forms can trigger webhooks when a form is submitted. Enables real-time processing without polling the form service's API.

E-commerce Events

Shopify, WooCommerce, and other platforms send webhooks for new orders, inventory changes, customer registrations, and fulfillment updates. Core to e-commerce notification workflows.

Monitoring and Alerting

Infrastructure monitoring tools send webhooks when thresholds are breached, services go down, or anomalies are detected. Powers automated alert notifications to team channels.

Webhook Security

Because webhooks involve receiving HTTP requests from external sources, security is a critical concern. Without proper verification, an attacker could send fake webhook requests to your endpoint to trigger unauthorized actions in your application. Here are the security practices every webhook implementation should follow.

HMAC Signature Verification

The most common and effective webhook security mechanism is HMAC (Hash-based Message Authentication Code) signature verification. The source application and your application share a secret key. When the source sends a webhook, it computes an HMAC hash of the request body using the shared secret and includes the hash in a request header. Your application computes the same hash and compares it. If the hashes match, the request is genuine.

// Verifying a webhook HMAC signature (Node.js / Express)
const crypto = require('crypto');

function verifyWebhookSignature(req, secret) {
  const signature = req.headers['x-webhook-signature'];
  const payload = JSON.stringify(req.body);

  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post('/webhooks/notifications', (req, res) => {
  if (!verifyWebhookSignature(req, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Signature verified -- safe to process the event
  const event = req.body;
  console.log('Received event:', event.event, event.data);

  res.status(200).json({ received: true });
});

Important: Always use crypto.timingSafeEqual() (or equivalent) for comparing signatures. Standard string comparison (===) is vulnerable to timing attacks where an attacker can determine the correct signature one character at a time by measuring response times.

Additional Security Measures

Beyond HMAC verification, there are several additional practices to harden your webhook endpoints.

Webhook Implementation Patterns

How you process incoming webhooks significantly affects the reliability and performance of your integration. Here are the patterns that work best in production.

Acknowledge First, Process Later

The most important webhook implementation pattern is: respond with HTTP 200 immediately, then process the event asynchronously. Webhook providers have timeout thresholds (typically 5-30 seconds). If your endpoint does not respond in time, the provider treats the delivery as failed and retries. If your event processing takes longer than the timeout -- querying a database, calling external APIs, sending notifications -- you will receive duplicate webhooks.

// Pattern: Acknowledge immediately, process asynchronously
app.post('/webhooks/orders', async (req, res) => {
  // 1. Verify signature
  if (!verifySignature(req)) {
    return res.status(401).send('Unauthorized');
  }

  // 2. Acknowledge receipt immediately
  res.status(200).json({ received: true });

  // 3. Queue the event for async processing
  await eventQueue.add('process-webhook', {
    event: req.body.event,
    data: req.body.data,
    received_at: new Date()
  });
});

// 4. Process the event in a background worker
eventQueue.process('process-webhook', async (job) => {
  const { event, data } = job.data;

  if (event === 'order.created') {
    // Send notification via One-Ping
    await fetch('https://api.one-ping.com/send', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer YOUR_API_KEY'
      },
      body: JSON.stringify({
        message: `New order #${data.order_id}: $${data.total} from ${data.customer_name}`,
        channels: ['slack', 'telegram'],
        recipient: '[email protected]'
      })
    });
  }
});

Idempotency with Event IDs

Since webhook providers may send the same event multiple times (due to retries, network issues, or your server restarting during processing), your handler must be idempotent. The standard approach is to store the event ID when you process it, and check for duplicates before processing a new webhook. If you have already processed an event with the same ID, skip it.

Event Ordering

Webhooks are not guaranteed to arrive in the order events occurred. A "payment.succeeded" webhook might arrive before the "payment.created" webhook due to network timing. Design your event processing to handle out-of-order delivery. Use timestamps in the event payload to determine the correct sequence, and use idempotent state updates (set the status to "paid" regardless of current state, rather than transitioning from "pending" to "paid").

Dead Letter Handling

Some webhook events will fail to process due to bugs in your handler, database errors, or dependent service outages. Instead of losing these events, implement a dead-letter pattern: move failed events to a separate queue or database table where they can be investigated and reprocessed once the issue is resolved. This prevents data loss and gives you a clear view of what went wrong.

Webhooks in Notification Systems

In the context of notification infrastructure, webhooks serve two critical purposes: as a trigger mechanism for sending notifications, and as a feedback mechanism for tracking delivery status.

Webhooks as Notification Triggers

Many notification workflows start with a webhook. An e-commerce platform sends a webhook when an order is placed. Your application receives the webhook and triggers a notification to the customer via email and Telegram. A monitoring service sends a webhook when a server's CPU exceeds 90%. Your application receives it and sends an alert to your ops team via Slack and Discord. Webhooks are the event source that drives the notification.

Automation tools like n8n and Zapier are built on this pattern. They listen for incoming webhooks, process the event data, and trigger actions -- including sending notifications through APIs like One-Ping. This webhook-to-notification pipeline is one of the most common integration patterns in modern applications.

Webhooks as Delivery Callbacks

When you send a notification through a notification API, you often need to know what happened after the message was dispatched. Was it delivered? Did it bounce? Did the recipient open it? Delivery callback webhooks provide this information in real time. The notification API sends a webhook to your application whenever a message changes state -- queued, sent, delivered, bounced, opened, clicked.

This feedback loop is essential for building reliable transactional notification systems. If a password reset email bounces, you need to know immediately so you can offer the user an alternative delivery method. If a security alert is not delivered to any channel, you need to escalate. Delivery callback webhooks give you the visibility to build these recovery flows.

How One-Ping Uses Webhooks

One-Ping integrates with webhooks in both directions. You can use incoming webhooks from external services as triggers to send multi-channel notifications through One-Ping. And One-Ping sends delivery status webhooks back to your application so you can track every notification from dispatch to delivery.

// Receive a webhook from Shopify, send a notification via One-Ping
app.post('/webhooks/shopify/order-created', async (req, res) => {
  res.status(200).json({ received: true });

  const order = req.body;

  // Notify the customer on their preferred channels
  await fetch('https://api.one-ping.com/send', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: JSON.stringify({
      message: `Order confirmed! #${order.order_number} - ${order.line_items.length} items totaling $${order.total_price}. We'll notify you when it ships.`,
      channels: ['email', 'telegram'],
      recipient: order.customer.email
    })
  });

  // Notify the sales team on Slack
  await fetch('https://api.one-ping.com/send', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: JSON.stringify({
      message: `New order! #${order.order_number} from ${order.customer.first_name} ${order.customer.last_name} - $${order.total_price}`,
      channels: ['slack'],
      recipient: 'sales-channel'
    })
  });
});

This pattern -- receiving a webhook event and fanning it out into multi-channel notifications -- is at the heart of most One-Ping integrations. Whether the trigger comes from an e-commerce platform, a payment processor, a monitoring service, or a custom application, One-Ping turns the event into notifications across Telegram, email, Slack, Discord, or any combination of channels. The webhook provides the event. One-Ping provides the delivery.

Ready to simplify your notifications?

Start free with 100 messages/month. No credit card required.

Get started free