Skip to content

Webhooks Intro

DodaTech 5 min read

title: "Introduction to Webhooks" description: "Learn what webhooks are, how they enable event-driven server-to-server communication, and why they are essential for modern API integrations." weight: 11 date: 2026-06-28 lastmod: 2026-06-28 tags: ["apis", "webhooks"]


Webhooks are user-defined HTTP callbacks that are triggered by specific events. When an event occurs, the source site makes an HTTP request to the URL configured for the webhook, enabling real-time server-to-server communication.

## What You'll Learn

- What webhooks are and how they work
- Webhooks vs polling
- Common webhook use cases
- Webhook architecture overview
- Security considerations

## Why It Matters

Webhooks are the backbone of modern API integrations. They enable real-time event notifications between services without polling, reducing latency and server load.

## Real-World Use

A SaaS platform uses webhooks to notify a customer's CRM when a new subscription is created. The CRM receives the subscription data via HTTP POST within seconds, triggering automated workflows without manual polling.

## Flow Chart

```mermaid
flowchart LR
    A[Event Source] -->|Event Occurs| B{Webhook Trigger}
    B --> C[HTTP POST to URL]
    C --> D[Consumer Server]
    D --> E[Process Event]
    D --> F[Acknowledge 200 OK]

Code Examples

Example 1: Simple Webhook Server

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    data = request.json
    
    # Validate webhook
    event_type = request.headers.get('X-Event-Type')
    signature = request.headers.get('X-Signature')
    
    print(f"Received webhook: {event_type}")
    print(f"Payload: {data}")
    
    # Process the event
    if event_type == 'order.created':
        process_order(data)
    elif event_type == 'payment.received':
        process_payment(data)
    
    # Acknowledge receipt
    return jsonify({"status": "received"}), 200

def process_order(data):
    order_id = data.get('id')
    customer = data.get('customer')
    # Process the order
    print(f"Processing order {order_id} for {customer}")

def process_payment(data):
    transaction_id = data.get('transaction_id')
    amount = data.get('amount')
    print(f"Processing payment {transaction_id}: ${amount}")

if __name__ == '__main__':
    app.run(port=8080)

Expected output: Webhook server receives POST requests, validates headers, processes different event types, and returns 200 OK.

Example 2: Sending a Webhook from a Provider

const https = require('https');

async function sendWebhook(url, eventType, payload) {
  const data = JSON.stringify({
    event: eventType,
    timestamp: new Date().toISOString(),
    data: payload,
  });

  return new Promise((resolve, reject) => {
    const req = https.request(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(data),
        'X-Event-Type': eventType,
        'X-Signature': generateSignature(data),
        'X-Delivery-Attempt': '1',
      },
      timeout: 10000,
    }, (res) => {
      let body = '';
      res.on('data', chunk => body += chunk);
      res.on('end', () => {
        if (res.statusCode >= 200 && res.statusCode < 300) {
          resolve({ success: true, statusCode: res.statusCode });
        } else {
          resolve({ success: false, statusCode: res.statusCode, body });
        }
      });
    });

    req.on('error', reject);
    req.on('timeout', () => {
      req.destroy();
      reject(new Error('Request timeout'));
    });

    req.write(data);
    req.end();
  });
}

function generateSignature(payload) {
  const crypto = require('crypto');
  const secret = process.env.WEBHOOK_SECRET;
  return crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
}

// Usage
sendWebhook(
  'https://consumer.example.com/webhook',
  'user.created',
  { id: 123, email: 'user@example.com' }
).then(console.log).catch(console.error);

Expected output: Provider sends signed webhook POST request and receives acknowledgment from consumer.

Example 3: Webhook Registration Flow

const express = require('express');
const app = express();

app.use(express.json());

// In-memory webhook subscriptions
const webhooks = [];

// Register webhook
app.post('/api/webhooks/register', (req, res) => {
  const { url, events, secret } = req.body;

  if (!url || !events || !Array.isArray(events)) {
    return res.status(400).json({ error: 'url and events required' });
  }

  const webhook = {
    id: generateId(),
    url,
    events,
    secret: secret || generateSecret(),
    status: 'active',
    createdAt: new Date().toISOString(),
    stats: { sent: 0, failed: 0, lastDelivery: null },
  };

  webhooks.push(webhook);
  
  // Send test webhook to verify
  sendTestWebhook(webhook);

  res.status(201).json({
    id: webhook.id,
    secret: webhook.secret, // Return once
    url: webhook.url,
    events: webhook.events,
  });
});

// List webhooks
app.get('/api/webhooks', (req, res) => {
  res.json(webhooks.map(w => ({
    id: w.id,
    url: w.url,
    events: w.events,
    status: w.status,
    stats: w.stats,
  })));
});

// Delete webhook
app.delete('/api/webhooks/:id', (req, res) => {
  const index = webhooks.findIndex(w => w.id === req.params.id);
  if (index === -1) return res.status(404).json({ error: 'Not found' });
  webhooks.splice(index, 1);
  res.status(204).end();
});

function generateId() {
  return Math.random().toString(36).substring(2, 15);
}

function generateSecret() {
  const crypto = require('crypto');
  return crypto.randomBytes(32).toString('hex');
}

app.listen(3000);

Expected output: REST API for registering, listing, and deleting webhook subscriptions with auto-generated secrets.

Common Mistakes

Mistake Explanation
Not verifying webhook signatures Without signature verification, anyone can send fake events to your endpoint
Returning non-2xx for successful processing Always return 200 OK to acknowledge receipt; non-2xx triggers retries
Processing webhooks synchronously for long tasks Acknowledge immediately (200) and process asynchronously to avoid timeouts
Not handling webhook retries Consumers should handle duplicate deliveries idempotently
Storing secrets insecurely Webhook signing secrets must be stored encrypted, never in source code

Practice Questions

  1. What is the difference between webhooks and polling?
  2. How does a webhook provider know where to send events?
  3. What HTTP method do webhooks typically use?
  4. What should a consumer return to acknowledge a webhook?
  5. Why are webhook signatures important?

Challenge

Build a webhook provider that allows users to register webhook URLs for specific events. When events occur, send signed POST requests to all registered URLs. Include a verification mechanism (challenge-response) when registering a webhook.

FAQ

What is the difference between webhooks and APIs?

APIs are request-driven (you ask for data), webhooks are event-driven (data is sent to you). Webhooks are the reverse of the traditional API pattern.

Are webhooks synchronous or asynchronous?

Webhook delivery is asynchronous from the event source. The provider sends the webhook after the event occurs, not blocking the event creation.

Can webhooks be sent over HTTPS?

Yes, always use HTTPS for webhook endpoints to encrypt the payload in transit and verify the server identity.

What is a dead webhook?

A dead webhook is a registered URL that no longer responds successfully. Providers should detect dead webhooks and alert the subscriber.

How many webhooks can a system handle?

It depends on infrastructure. A well-designed system can handle millions of webhook deliveries per day with proper queuing and scaling.

Do webhooks guarantee delivery?

Most providers guarantee at-least-once delivery with retry logic. Some offer exactly-once delivery with idempotency keys.

Mini Project

Build a webhook provider service that allows users to register webhooks, sends signed HTTP POST requests on events, and provides delivery logs. Include a webhook simulator for testing consumer endpoints.

What's Next

Learn the differences between webhooks and polling

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro