Documentation

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

  1. You expose a public HTTPS endpoint on your server
  2. Chatbase sends HTTP POST requests to that URL when events occur
  3. Your server processes the payload and responds with 200 OK

Setting Up Your Webhook

In the CRM dashboard → IntegrationsWhatsAppWebhook 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

EventDescription
messageInbound message received from a customer
message_statusDelivery status update (sent, delivered, read, failed)
template_statusTemplate approved, rejected, or flagged by Meta
phone_number_qualityPhone 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: sentdeliveredread (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 OK immediately, then process asynchronously. If Chatbase doesn't receive 200 within 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:

AttemptDelay
1st retry5 seconds
2nd retry30 seconds
3rd retry5 minutes
4th retry30 minutes

After 4 failed retries the event is dropped and logged in the dashboard.