Integration
Advanced
4.6
18 min read
25.1K views

Webhook Configuration

Set up and handle webhooks to receive real-time updates from WhatsApp Business API. Learn how to configure webhooks for message status, incoming messages, and account updates.

What You'll Learn

  • • How to configure webhook endpoints
  • • Understanding webhook events and payloads
  • • Implementing webhook security and verification
  • • Handling different webhook event types
  • • Troubleshooting webhook issues

What are Webhooks?

Webhooks are HTTP callbacks that allow CMzon to send real-time updates to your application when specific events occur. This enables you to respond immediately to incoming messages, track message delivery status, and handle account updates.

Key Benefits

  • Real-time updates: Get instant notifications when events occur
  • No polling required: Eliminates the need to constantly check for updates
  • Efficient: Reduces API calls and improves performance
  • Reliable: Built-in retry mechanism for failed deliveries

Webhook Events

CMzon sends different types of webhook events based on the activities in your WhatsApp Business API account.

messages

Triggered when you receive incoming messages from customers.

Example Payload
{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "display_phone_number": "1234567890",
          "phone_number_id": "PHONE_NUMBER_ID"
        },
        "messages": [{
          "from": "1234567890",
          "id": "wamid.xxx",
          "timestamp": "1234567890",
          "text": {
            "body": "Hello, I need help with my order"
          },
          "type": "text"
        }]
      },
      "field": "messages"
    }]
  }]
}

message_status

Triggered when the status of a sent message changes (delivered, read, failed).

Example Payload
{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "display_phone_number": "1234567890",
          "phone_number_id": "PHONE_NUMBER_ID"
        },
        "statuses": [{
          "id": "wamid.xxx",
          "status": "delivered",
          "timestamp": "1234567890",
          "recipient_id": "1234567890"
        }]
      },
      "field": "messages"
    }]
  }]
}

message_errors

Triggered when a message fails to send or encounters an error.

Example Payload
{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
    "changes": [{
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "display_phone_number": "1234567890",
          "phone_number_id": "PHONE_NUMBER_ID"
        },
        "errors": [{
          "code": 131026,
          "title": "Message undeliverable",
          "message": "The message could not be delivered",
          "error_data": {
            "details": "Recipient phone number is not a WhatsApp number"
          }
        }]
      },
      "field": "messages"
    }]
  }]
}

Webhook Configuration

Step 1: Set Up Your Webhook Endpoint

First, you need to create a webhook endpoint that can receive HTTP POST requests from CMzon.

1

Create HTTPS Endpoint

Your webhook endpoint must be accessible via HTTPS. CMzon will not send webhooks to HTTP endpoints.

2

Handle POST Requests

Your endpoint should accept POST requests and respond with a 200 status code for successful processing.

3

Implement Verification

Implement webhook verification to ensure requests are coming from CMzon and not malicious sources.

Step 2: Configure in CMzon Dashboard

Dashboard Configuration

1
Go to Webhook Settings

Navigate to your CMzon dashboard → Settings → Webhooks

2
Enter Webhook URL

Enter your HTTPS webhook endpoint URL (e.g., https://yourdomain.com/webhook)

3
Select Events

Choose which events you want to receive (messages, message_status, message_errors)

4
Verify Webhook

Click "Verify Webhook" to test the connection and verify your endpoint

Implementation Examples

Node.js Express Example

Express Webhook Handler
const express = require('express');
const crypto = require('crypto');
const app = express();

// Middleware to parse JSON
app.use(express.json());

// Webhook verification
const verifyWebhook = (req, res, next) => {
  const signature = req.headers['x-hub-signature-256'];
  const payload = JSON.stringify(req.body);
  const expectedSignature = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (signature !== `sha256=${expectedSignature}`) {
    return res.status(401).send('Unauthorized');
  }
  
  next();
};

// Webhook endpoint
app.post('/webhook', verifyWebhook, (req, res) => {
  const body = req.body;
  
  // Check if it's a webhook verification request
  if (body.object === 'whatsapp_business_account') {
    body.entry.forEach(entry => {
      entry.changes.forEach(change => {
        if (change.field === 'messages') {
          const value = change.value;
          
          // Handle incoming messages
          if (value.messages) {
            value.messages.forEach(message => {
              console.log('Received message:', message);
              handleIncomingMessage(message);
            });
          }
          
          // Handle message status updates
          if (value.statuses) {
            value.statuses.forEach(status => {
              console.log('Message status:', status);
              handleMessageStatus(status);
            });
          }
          
          // Handle message errors
          if (value.errors) {
            value.errors.forEach(error => {
              console.log('Message error:', error);
              handleMessageError(error);
            });
          }
        }
      });
    });
  }
  
  res.status(200).send('OK');
});

// Handle incoming messages
function handleIncomingMessage(message) {
  const from = message.from;
  const messageId = message.id;
  const messageType = message.type;
  
  if (messageType === 'text') {
    const text = message.text.body;
    console.log(`Text message from ${from}: ${text}`);
    
    // Process the message and send response
    processTextMessage(from, text);
  } else if (messageType === 'image') {
    const image = message.image;
    console.log(`Image message from ${from}: ${image.id}`);
    
    // Handle image message
    processImageMessage(from, image);
  }
}

// Handle message status updates
function handleMessageStatus(status) {
  const messageId = status.id;
  const statusType = status.status;
  const timestamp = status.timestamp;
  
  console.log(`Message ${messageId} status: ${statusType} at ${timestamp}`);
  
  // Update your database with the status
  updateMessageStatus(messageId, statusType, timestamp);
}

// Handle message errors
function handleMessageError(error) {
  const code = error.code;
  const title = error.title;
  const message = error.message;
  
  console.error(`Message error ${code}: ${title} - ${message}`);
  
  // Handle the error appropriately
  handleError(code, title, message);
}

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Webhook server running on port ${PORT}`);
});

Python Flask Example

Flask Webhook Handler
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
import os

app = Flask(__name__)

def verify_webhook_signature(payload, signature):
    """Verify webhook signature"""
    expected_signature = hmac.new(
        os.getenv('WEBHOOK_SECRET').encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(f'sha256={expected_signature}', signature)

@app.route('/webhook', methods=['POST'])
def webhook():
    # Get the signature from headers
    signature = request.headers.get('X-Hub-Signature-256')
    
    # Verify the signature
    if not verify_webhook_signature(request.get_data(), signature):
        return jsonify({'error': 'Unauthorized'}), 401
    
    # Parse the webhook payload
    body = request.get_json()
    
    # Process the webhook
    if body.get('object') == 'whatsapp_business_account':
        for entry in body.get('entry', []):
            for change in entry.get('changes', []):
                if change.get('field') == 'messages':
                    value = change.get('value', {})
                    
                    # Handle incoming messages
                    for message in value.get('messages', []):
                        handle_incoming_message(message)
                    
                    # Handle message status updates
                    for status in value.get('statuses', []):
                        handle_message_status(status)
                    
                    # Handle message errors
                    for error in value.get('errors', []):
                        handle_message_error(error)
    
    return jsonify({'status': 'success'}), 200

def handle_incoming_message(message):
    """Handle incoming messages"""
    from_number = message.get('from')
    message_id = message.get('id')
    message_type = message.get('type')
    
    if message_type == 'text':
        text = message.get('text', {}).get('body', '')
        print(f"Text message from {from_number}: {text}")
        
        # Process text message
        process_text_message(from_number, text)
    
    elif message_type == 'image':
        image = message.get('image', {})
        print(f"Image message from {from_number}: {image.get('id')}")
        
        # Process image message
        process_image_message(from_number, image)

def handle_message_status(status):
    """Handle message status updates"""
    message_id = status.get('id')
    status_type = status.get('status')
    timestamp = status.get('timestamp')
    
    print(f"Message {message_id} status: {status_type} at {timestamp}")
    
    # Update database with status
    update_message_status(message_id, status_type, timestamp)

def handle_message_error(error):
    """Handle message errors"""
    code = error.get('code')
    title = error.get('title')
    message = error.get('message')
    
    print(f"Message error {code}: {title} - {message}")
    
    # Handle the error
    handle_error(code, title, message)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=3000, debug=True)

Webhook Security

Critical Security Requirements

  • Always verify webhook signatures to ensure requests are from CMzon
  • Use HTTPS only - HTTP endpoints will be rejected
  • Implement rate limiting to prevent abuse
  • Log all webhook events for debugging and security monitoring
  • Handle errors gracefully and return appropriate HTTP status codes

Signature Verification

Always verify the webhook signature to ensure the request is authentic.

// Node.js example const signature = req.headers['x-hub-signature-256']; const expectedSignature = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(JSON.stringify(req.body)) .digest('hex');

Response Requirements

  • • Return 200 OK for successful processing
  • • Return 4xx for client errors
  • • Return 5xx for server errors
  • • Respond within 30 seconds
  • • Handle duplicate events gracefully

Troubleshooting

Webhook Not Receiving Events

  • • Check if your endpoint is accessible via HTTPS
  • • Verify the webhook URL is correct in your dashboard
  • • Ensure your server is responding with 200 OK
  • • Check firewall and network settings
  • • Verify SSL certificate is valid

Signature Verification Failing

  • • Ensure you're using the correct webhook secret
  • • Check that you're using the raw request body
  • • Verify the signature algorithm (HMAC-SHA256)
  • • Make sure the signature header format is correct

Duplicate Events

  • • Implement idempotency using message IDs
  • • Store processed event IDs to prevent duplicates
  • • Use database constraints to prevent duplicate processing
  • • Handle retry scenarios gracefully

Need Help with Webhooks?

Our integration team can help you set up webhooks and resolve any configuration issues.