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.
{ "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).
{ "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.
{ "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.
Create HTTPS Endpoint
Your webhook endpoint must be accessible via HTTPS. CMzon will not send webhooks to HTTP endpoints.
Handle POST Requests
Your endpoint should accept POST requests and respond with a 200 status code for successful processing.
Implement Verification
Implement webhook verification to ensure requests are coming from CMzon and not malicious sources.
Step 2: Configure in CMzon Dashboard
Dashboard Configuration
Go to Webhook Settings
Navigate to your CMzon dashboard → Settings → Webhooks
Enter Webhook URL
Enter your HTTPS webhook endpoint URL (e.g., https://yourdomain.com/webhook)
Select Events
Choose which events you want to receive (messages, message_status, message_errors)
Verify Webhook
Click "Verify Webhook" to test the connection and verify your endpoint
Implementation Examples
Node.js Express Example
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
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.