Webhooks are the backbone of modern automation. Instead of constantly checking for updates, you get notified automatically when something happens. In this guide, we explain webhooks from scratch: what they are, how they work, and how to use them in practice.

Before you read on
Does automation actually pay off for you? Take the 5-minute analysis — score, maturity level and an honest read on whether this path fits your situation. Free, report by email.
Start 5-min analysis →

What is a Webhook?

Simple Explanation:

A webhook is like a doorbell. Instead of checking the door every 5 minutes (polling), the visitor rings the bell and you get notified immediately. Webhooks are a core concept in API integration and essential for real-time automation.

Technical:

A webhook is an HTTP POST request that a service sends to your URL when an event occurs.

Polling vs. Webhook

AspectPollingWebhook
InitiatorYou askService notifies you
LatencyMinutes (depending on interval)Real-time (seconds)
ResourcesMany unnecessary requestsOnly on events
ComplexityEasier to set upRequires public URL

How Do Webhooks Work?

The Flow

1. You register your URL with the service
        |
2. Event occurs (e.g., new order)
        |
3. Service sends POST request to your URL
        |
4. Your server receives the data
        |
5. You process the data
        |
6. You respond with 200 OK

A Typical Webhook Request

POST /webhook/orders HTTP/1.1
Host: your-domain.com
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...

{
  "event": "order.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "orderId": "12345",
    "customerEmail": "customer@example.com",
    "total": 99.00
  }
}

Creating a Webhook Endpoint

Option 1: n8n Webhook

Step 1: Add Webhook Node

  • Create new workflow
  • Add "Webhook" node
  • Configuration:
  • - HTTP Method: POST

    - Path: orders (becomes /webhook/orders)

    - Response Mode: When Last Node Finishes

    Step 2: Copy URL

    n8n shows two URLs:

    • Test URL: For development (only when workflow is open)
    • Production URL: For live operation (after activation)

    Test: https://n8n.your-domain.com/webhook-test/orders
    Prod: https://n8n.your-domain.com/webhook/orders

    Step 3: Process Data

    // Node: Code
    // Process webhook data
    
    const event = $json.body.event;
    const data = $json.body.data;
    
    console.log(`Event: ${event}`);
    console.log(`Order ID: ${data.orderId}`);
    
    return {
      orderId: data.orderId,
      email: data.customerEmail,
      total: data.total,
      processedAt: new Date().toISOString()
    };

    Option 2: Make.com Webhook

    Step 1: Create Custom Webhook

  • New scenario
  • Trigger: "Webhooks" -> "Custom webhook"
  • Click "Add" -> Give it a name
  • Copy URL
  • https://hook.eu1.make.com/abc123xyz456

    Step 2: Define Structure

    Either:

    • Automatically on first request
    • Or manually in "Data structure" tab

    Option 3: Your Own Server (Node.js)

    const express = require('express');
    const app = express();
    
    app.use(express.json());
    
    app.post('/webhook/orders', (req, res) => {
      const { event, data } = req.body;
    
      console.log('Webhook received:', event);
    
      // Here: Process data
      processOrder(data);
    
      // Always respond with 200 OK (quickly!)
      res.status(200).json({ received: true });
    });
    
    app.listen(3000);

    Build it or have it built?
    We implement this workflow for you — fully tested in 1-4 weeks. Fixed-price quote within 24h.
    Get a Quote →

    Securing Webhooks

    1. Signature Verification

    Most services sign their webhooks:

    const crypto = require('crypto');
    
    function verifySignature(payload, signature, secret) {
      const computed = crypto
        .createHmac('sha256', secret)
        .update(payload)
        .digest('hex');
    
      return computed === signature;
    }
    
    // In your webhook handler:
    const isValid = verifySignature(
      JSON.stringify(req.body),
      req.headers['x-webhook-signature'],
      process.env.WEBHOOK_SECRET
    );
    
    if (!isValid) {
      return res.status(401).json({ error: 'Invalid signature' });
    }

    2. IP Whitelisting

    Only accept requests from known IPs:

    const allowedIPs = ['192.168.1.1', '10.0.0.1'];
    
    if (!allowedIPs.includes(req.ip)) {
      return res.status(403).json({ error: 'IP not allowed' });
    }

    3. Use HTTPS

    Webhooks should ALWAYS run over HTTPS, never HTTP.

    4. Timestamp Validation

    Reject old requests (prevent replay attacks):

    const timestamp = parseInt(req.headers['x-webhook-timestamp']);
    const now = Math.floor(Date.now() / 1000);
    
    if (now - timestamp > 300) { // Older than 5 minutes
      return res.status(400).json({ error: 'Request too old' });
    }

    Practical Examples

    Example 1: Shopify Order Webhook

    Register webhook (Shopify Admin):

  • Settings -> Notifications -> Webhooks
  • "Create webhook" -> Event: "Order creation"
  • URL: Your n8n/Make.com URL
  • Format: JSON
  • Payload example:

    {
      "id": 820982911946154500,
      "email": "customer@example.com",
      "created_at": "2024-01-15T10:30:00+01:00",
      "total_price": "199.00",
      "line_items": [
        {
          "title": "Product A",
          "quantity": 2,
          "price": "99.50"
        }
      ]
    }

    n8n Workflow:

    Shopify Webhook
            |
        Extract data
            |
        Parallel:
        |-- Google Sheets: Log order
        |-- Email: Send confirmation
        +-- Slack: Notify team

    For a complete Stripe integration walkthrough, see our dedicated Stripe webhook setup guide.

    Example 2: Stripe Payment Webhook

    Register webhook:

    # Stripe Dashboard or CLI
    stripe webhooks create \
      --url https://n8n.your-domain.com/webhook/stripe \
      --events payment_intent.succeeded,payment_intent.failed

    Process payload:

    // Node: Switch - By event type
    const eventType = $json.type;
    
    switch(eventType) {
      case 'payment_intent.succeeded':
        return { route: 'success' };
      case 'payment_intent.failed':
        return { route: 'failed' };
      default:
        return { route: 'ignore' };
    }

    Example 3: GitHub Push Webhook

    Set up webhook:

  • Repository -> Settings -> Webhooks -> Add webhook
  • URL: Your webhook URL
  • Content type: application/json
  • Events: Push events
  • Usage:

    GitHub Push Webhook
            |
        Branch = "main"?
            | Yes
        SSH: Run deploy script
            |
        Slack: Notify about deployment

    Example 4: Typeform Response Webhook

    Enable webhook:

  • Typeform -> Connect -> Webhooks
  • Enter URL
  • Send test
  • Use data:

    // Typeform sends answers in structured format
    const answers = $json.form_response.answers;
    
    const name = answers.find(a => a.field.ref === 'name')?.text;
    const email = answers.find(a => a.field.ref === 'email')?.email;
    const message = answers.find(a => a.field.ref === 'message')?.text;
    
    return { name, email, message };

    Webhook Debugging

    Local Development

    Problem: Webhooks need a public URL.

    Solution 1: ngrok

    # Install ngrok
    brew install ngrok
    
    # Start tunnel
    ngrok http 5678
    
    # Shows public URL
    # https://abc123.ngrok.io -> localhost:5678

    Solution 2: Stripe CLI

    stripe listen --forward-to localhost:5678/webhook/stripe

    Request Inspection

    Tool: RequestBin / Webhook.site

  • Open https://webhook.site
  • Copy unique URL
  • Use as webhook endpoint
  • All requests are displayed
  • n8n Debug

  • Open workflow
  • Activate "Test Workflow"
  • Send webhook
  • Inspect data in each node
  • Training or implementation?
    Whether you want to learn it yourself or have us build it — we offer both. Custom workshops from 2h or turnkey solutions.
    See Options →

    Error Handling

    Retries

    If your endpoint fails, many services retry:

    ServiceRetry Behavior
    Stripe3 days, exponential backoff
    Shopify19 attempts, 48 hours
    GitHub3 attempts

    Idempotency

    Webhooks can be delivered multiple times. Process each event only once:

    // Save webhook ID
    const webhookId = $json.id;
    
    // Check if already processed
    const existing = await db.get('processed_webhooks', webhookId);
    if (existing) {
      return { status: 'already_processed' };
    }
    
    // Process
    await processWebhook($json);
    
    // Mark as processed
    await db.set('processed_webhooks', webhookId, {
      processedAt: new Date().toISOString()
    });

    Async Processing

    Respond quickly, process later:

    app.post('/webhook', async (req, res) => {
      // Respond immediately
      res.status(200).json({ received: true });
    
      // Process async (after response)
      setImmediate(async () => {
        try {
          await processWebhook(req.body);
        } catch (error) {
          console.error('Webhook processing failed:', error);
          await alertTeam(error);
        }
      });
    });

    Creating Webhook Documentation

    If you offer your own webhooks, document them:

    ## Order Created Webhook
    
    ### Trigger
    Fired when a new order is created.
    
    ### HTTP Request
    - Method: POST
    - Content-Type: application/json
    
    ### Headers
    | Header | Description |
    |--------|-------------|
    | X-Webhook-Signature | HMAC-SHA256 signature |
    | X-Webhook-Timestamp | Unix timestamp |
    
    ### Payload
    json

    {

    "event": "order.created",

    "data": {

    "orderId": "string",

    "customerEmail": "string",

    "total": "number"

    }

    }

    ### Response
    Respond with HTTP 200 within 30 seconds.

    Costs

    SolutionCost
    n8n CloudFrom $20/month
    Make.comFrom $9/month
    Own ServerFrom $5/month (VPS)
    Serverless (AWS Lambda)Pay-per-use

    Conclusion

    Webhooks are fundamental to modern automation:

    • Real-time processing instead of polling
    • Resource-efficient
    • Easy to implement with n8n/Make.com

    Next Steps

  • Create webhook endpoint (n8n recommended)
  • Register with a service (e.g., Shopify, Stripe)
  • Implement signature verification
  • Add error handling
  • Go live
  • We can help you with webhook integration, from setup to production.