Webhooks
Receive real-time delivery receipts and inbound messages via webhooks
Webhooks
Webhooks let Chatbase push events to your server in real time — delivery receipts, inbound messages, template status changes, and more.
How It Works
- You expose a public HTTPS endpoint on your server
- Chatbase sends HTTP POST requests to that URL when events occur
- Your server processes the payload and responds with
200 OK
Setting Up Your Webhook
In the CRM dashboard → Integrations → WhatsApp → Webhook Settings, enter your endpoint URL. Chatbase will send a verification challenge to confirm ownership.
Verification Challenge
When you save a new webhook URL, Chatbase sends a GET request with query parameters:
GET https://your-server.com/webhook?hub.mode=subscribe&hub.verify_token=YOUR_TOKEN&hub.challenge=RANDOM_STRING
Your endpoint must respond with the hub.challenge value and status 200:
app.get('/webhook', (req, res) => {
const { 'hub.mode': mode, 'hub.verify_token': token, 'hub.challenge': challenge } = req.query;
if (mode === 'subscribe' && token === process.env.WEBHOOK_VERIFY_TOKEN) {
res.status(200).send(challenge);
} else {
res.sendStatus(403);
}
});
Event Types
| Event | Description |
|---|---|
message | Inbound message received from a customer |
message_status | Delivery status update (sent, delivered, read, failed) |
template_status | Template approved, rejected, or flagged by Meta |
phone_number_quality | Phone number quality score changed |
Payload Structure
Inbound Message
{
"event": "message",
"from": "919876543210",
"name": "Rahul Sharma",
"messageId": "wamid.HBgLOTE5ODc2NTQzMjEwFQ...",
"type": "text",
"text": { "body": "Hi, I need help with my order" },
"timestamp": "2024-06-10T09:30:00.000Z"
}
Delivery Status Update
{
"event": "message_status",
"messageId": "wamid.HBgLOTE5ODc2NTQzMjEwFQ...",
"to": "919876543210",
"status": "delivered",
"timestamp": "2024-06-10T09:30:05.000Z"
}
Status values: sent → delivered → read (or failed)
Template Status Change
{
"event": "template_status",
"templateName": "order_shipped",
"templateId": "1234567890",
"status": "APPROVED",
"timestamp": "2024-06-10T09:30:00.000Z"
}
Handling Webhook Events
app.post('/webhook', express.json(), (req, res) => {
// Respond immediately — Chatbase retries if it doesn't get 200 within 10 seconds
res.sendStatus(200);
const { event, ...payload } = req.body;
switch (event) {
case 'message':
handleInboundMessage(payload);
break;
case 'message_status':
updateMessageStatus(payload.messageId, payload.status);
break;
case 'template_status':
console.log(`Template ${payload.templateName} is now ${payload.status}`);
break;
}
});
Always respond
200 OKimmediately, then process asynchronously. If Chatbase doesn't receive200within 10 seconds it will retry.
Delivery Status via API
As an alternative to webhooks, you can poll the delivery status endpoint:
curl "https://chatbase.in/api/v1/whatsapp/messages?limit=50" \
-H "Authorization: Bearer wpapi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Webhook Security
Validate that incoming requests genuinely originate from Chatbase by checking the X-Chatbase-Signature header (HMAC-SHA256 of the raw body using your webhook secret):
const crypto = require('crypto');
function verifySignature(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-chatbase-signature'];
if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.sendStatus(401);
}
res.sendStatus(200);
// process req.body ...
});
Retry Policy
If your server is unavailable or returns a non-200 status, Chatbase retries with exponential back-off:
| Attempt | Delay |
|---|---|
| 1st retry | 5 seconds |
| 2nd retry | 30 seconds |
| 3rd retry | 5 minutes |
| 4th retry | 30 minutes |
After 4 failed retries the event is dropped and logged in the dashboard.