Webhook Settings

Loading account context...

Configure Customer Webhook

Events are tenant-isolated: only this logged-in account's WABA and phone events are sent.

Use public HTTPS endpoint. Local/private URLs are blocked for security.
Required if your endpoint validates X-Chatyug-Signature. Leave blank when saving to keep an existing secret.

Chatyug Webhook Setup Guide

  1. Create an HTTPS endpoint in your system.
  2. Save webhook URL above for your selected WABA.
  3. Use test event to validate connectivity.
  4. If your receiver validates signatures, enter the same secret here and on the receiver, then Save before testing.
  5. Use event id for idempotency in your receiver.

Headers sent by ChatYug: X-Chatyug-Event-Id, X-Chatyug-Signature (if secret exists).

Event types

eventTypeDescription
messageInbound text, media, button/list reply, Flow submission (nfm_reply)
statusOutbound message delivery receipts (sent, delivered, read, failed)
orderWhatsApp cart / catalog order from customer
testConnectivity test from this page

Sample: message (text)

{
  "eventType": "message",
  "userId": 34,
  "wabaId": "1957290828491918",
  "phoneNumberId": "1079034885291122",
  "eventId": "wamid.HBgM....",
  "occurredAt": "2026-04-28T10:10:00.000Z",
  "data": {
    "metadata": { "phone_number_id": "1079034885291122" },
    "message": { "id": "wamid....", "type": "text", "text": { "body": "hello" } }
  }
}

Sample: message (button reply)

{
  "eventType": "message",
  "data": {
    "message": {
      "type": "interactive",
      "interactive": {
        "type": "button_reply",
        "button_reply": { "id": "CONFIRM_YES", "title": "Yes" }
      }
    }
  }
}

Sample: message (list reply)

{
  "eventType": "message",
  "data": {
    "message": {
      "type": "interactive",
      "interactive": {
        "type": "list_reply",
        "list_reply": { "id": "PROJ_12", "title": "Project Alpha", "description": "Phase 2" }
      }
    }
  }
}

Sample: message (Flow nfm_reply)

When a customer completes a WhatsApp Flow, Meta delivers interactive.type = nfm_reply. Parse response_json (JSON string). Field keys match the designer Name on each input. Correlate with the flow_token you sent in POST /api/external/messages/flow. Full guide: Commerce Flows — receive filled data.

{
  "eventType": "message",
  "data": {
    "from": "919876543210",
    "message": {
      "id": "wamid.HBgM...",
      "type": "interactive",
      "interactive": {
        "type": "nfm_reply",
        "nfm_reply": {
          "name": "flow",
          "body": "Sent",
          "response_json": "{\"flow_token\":\"flow_1720856400000_abc\",\"customer_name\":\"Rahul\",\"city\":\"Bharuch\",\"mobile_number\":\"9876543210\"}"
        }
      }
    }
  }
}
// Node — parse filled fields
const reply = payload.data.message.interactive.nfm_reply;
const answers = JSON.parse(reply.response_json || '{}');
const token = answers.flow_token;           // same token from send
const name = answers.customer_name;        // designer field Name
// Look up your CRM order / lead by token, then store answers

Sample: status

{
  "eventType": "status",
  "eventId": "wamid.HBgM....",
  "data": {
    "status": {
      "id": "wamid....",
      "status": "delivered",
      "timestamp": "1719156600",
      "recipient_id": "919876543210"
    }
  }
}

Sample: order

{
  "eventType": "order",
  "data": {
    "order": {
      "catalog_id": "980328057290841",
      "product_items": [
        { "product_retailer_id": "SKU-001", "quantity": 1, "item_price": 599, "currency": "INR" }
      ]
    }
  }
}

Signature verification (Node.js)

const crypto = require('crypto');
function verifyChatyugSignature(rawBody, secret, signatureHeader) {
  if (!secret || !signatureHeader) return false;
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex');
  try {
    return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
  } catch { return false; }
}

Delivery: ChatYug automatically retries failed deliveries for up to 48 hours. Backoff: 1, 2, 10, 60 minutes (early attempts), then 6 hours for subsequent attempts. Rate limit ~300 events/min per WABA. Return HTTP 2xx within 8 seconds to acknowledge.