Skip to main content
Webhooks allow you to receive real-time HTTP notifications for WhatsApp events, including incoming messages and delivery status updates.

Creating a Webhook

Create a webhook for your application to start receiving WhatsApp events. Via Dashboard
  1. Navigate to your application’s Webhooks page
  2. Click “Create Webhook”
  3. Enter your webhook URL
  4. Select WhatsApp-related events
  5. (Optional) Add custom headers for authentication
  6. Save the webhook
Via API
Create Webhook
curl -X POST https://api.buildwithchirp.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_APP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/whatsapp",
    "events": [
      "messages.whatsapp.sent",
      "messages.whatsapp.delivered",
      "messages.whatsapp.read"
    ],
    "headers": {
      "X-Webhook-Secret": "your-secret-key"
    }
  }'

WhatsApp Events

EventDescription
messages.whatsapp.receivedInbound WhatsApp message received
messages.whatsapp.sentMessage sent to WhatsApp servers
messages.whatsapp.deliveredMessage delivered to user’s device
messages.whatsapp.readMessage read by the user
messages.whatsapp.failedMessage delivery failed

Event Payloads

Message Received

messages.whatsapp.received
{
  "event": "messages.whatsapp.received",
  "data": {
    "id": "msg_wa_2DbBs7GWhGvVNJGrDXr5RG0mBWI",
    "from": "+15551234567",
    "to": "+15559876543",
    "text": "Hello!",
    "type": "text",
    "receivedAt": "2024-01-15T12:00:00.000Z"
  }
}

Message Sent

messages.whatsapp.sent
{
  "event": "messages.whatsapp.sent",
  "data": {
    "id": "msg_wa_2DbBs7GWhGvVNJGrDXr5RG0mBWI",
    "status": "sent",
    "sentAt": "2024-01-15T12:00:00.000Z"
  }
}

Message Delivered

messages.whatsapp.delivered
{
  "event": "messages.whatsapp.delivered",
  "data": {
    "id": "msg_wa_2DbBs7GWhGvVNJGrDXr5RG0mBWI",
    "status": "delivered",
    "deliveredAt": "2024-01-15T12:00:05.000Z"
  }
}

Message Read

messages.whatsapp.read
{
  "event": "messages.whatsapp.read",
  "data": {
    "id": "msg_wa_2DbBs7GWhGvVNJGrDXr5RG0mBWI",
    "status": "read",
    "readAt": "2024-01-15T12:00:10.000Z"
  }
}

Message Failed

messages.whatsapp.failed
{
  "event": "messages.whatsapp.failed",
  "data": {
    "id": "msg_wa_2DbBs7GWhGvVNJGrDXr5RG0mBWI",
    "status": "failed",
    "failedAt": "2024-01-15T12:00:05.000Z",
    "error": {
      "type": "provider_error",
      "code": "message_undeliverable",
      "message": "Re-engagement message was not delivered",
      "provider": {
        "source": "meta",
        "code": 131047,
        "message": "Re-engagement message: Re-engagement message was not delivered"
      }
    }
  }
}
The error object uses the same format as API error responses, making it easy to handle errors consistently across your application. The error.code maps Meta’s error codes to Chirp’s standardized error codes, and the error.provider field preserves the original provider error details for debugging.

Response Requirements

Your webhook endpoint should:
  1. Respond within 5 seconds - Return 200 OK quickly
  2. Process asynchronously - Don’t block on long-running tasks
  3. Handle duplicates - Events may be delivered multiple times
Webhook Handler
app.post("/webhooks/whatsapp", (req, res) => {
  // Acknowledge immediately
  res.status(200).send("OK");

  // Process asynchronously
  processWhatsAppEvent(req.body).catch(console.error);
});

async function processWhatsAppEvent(payload) {
  const { event, data } = payload;

  switch (event) {
    case "messages.whatsapp.received":
      await handleIncomingMessage(data);
      break;
    case "messages.whatsapp.sent":
      await updateMessageStatus(data.id, "sent");
      break;
    case "messages.whatsapp.delivered":
      await updateMessageStatus(data.id, "delivered");
      break;
    case "messages.whatsapp.read":
      await updateMessageStatus(data.id, "read");
      break;
    case "messages.whatsapp.failed":
      await handleFailedMessage(data);
      break;
  }
}

Security Best Practices

Validate Request Origin

Use custom headers to verify requests are from Chirp:
Validate Webhook
app.post("/webhooks/whatsapp", (req, res) => {
  const secret = req.headers["x-webhook-secret"];

  if (secret !== process.env.WEBHOOK_SECRET) {
    return res.status(401).send("Unauthorized");
  }

  // Process webhook...
  res.status(200).send("OK");
});

Use HTTPS

Always use HTTPS URLs for webhook endpoints. HTTP is not supported.

Retry Behavior

If your webhook fails (non-200 status or timeout):
  • Chirp retries delivery with exponential backoff
  • Maximum 5 retry attempts
  • Failed webhooks are logged in your dashboard

Testing Webhooks

Use the Playground
  1. Configure a webhook on your test application
  2. Send test messages using the Playground
  3. Your webhook receives events in real-time
  4. View webhook delivery logs in the dashboard
Local Development Use tunneling tools for local testing:
  • ngrok - Create public URLs for local servers
  • webhook.site - Inspect webhook payloads
  • localtunnel - Simple local tunneling

Managing Webhooks

List Webhooks
curl https://api.buildwithchirp.com/v1/webhooks \
  -H "Authorization: Bearer YOUR_APP_KEY"
Update Webhook
curl -X PUT https://api.buildwithchirp.com/v1/webhooks/{webhookId} \
  -H "Authorization: Bearer YOUR_APP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["messages.whatsapp.delivered"]
  }'
Delete Webhook
curl -X DELETE https://api.buildwithchirp.com/v1/webhooks/{webhookId} \
  -H "Authorization: Bearer YOUR_APP_KEY"