Developers

Webhooks: real-time events

Updated 31 May 2026

Webhooks let Baat notify your systems the instant something happens — a contact is created, a conversation opens or closes, or a customer submits a WhatsApp Flow form. Instead of polling the API, you register a URL and Baat POSTs the event to it in real time. Manage them under Developers → Webhooks.

Creating a webhook

Click Add webhook and provide:

  • Name — e.g. CRM contact sync.

  • Endpoint URL — the HTTPS URL Baat will POST to, e.g. https://yourapp.com/webhooks/baat.

  • Event — which event this endpoint subscribes to (one event per webhook).

  • Custom auth header (optional) — a header name/value pair Baat adds to each delivery, so your endpoint can authenticate the caller (e.g. Authorization: Bearer …).

On creation Baat generates a signing secret and shows it once. Copy it into your secret store immediately — you’ll use it to verify that incoming requests genuinely came from Baat.

Available events

EventFires when…
contact.createdA new contact is added to your organization.
contact.updatedA contact’s tags or details change.
conversation.openedA conversation is opened or re-opened.
conversation.closedA conversation is closed.
flow_response.submittedA customer submits a WhatsApp Flow form.

Payload format

Baat sends a JSON POST with Content-Type: application/json. The body looks like:

{
  "event": "contact.created",
  "occurred_at": "2026-05-31T09:15:42Z",
  "organization_id": 4567,
  "data": {
    "...": "the full entity that triggered the event"
  }
}
FieldDescription
eventThe event key, e.g. contact.created.
occurred_atISO-8601 UTC timestamp of when the event happened.
organization_idYour Baat organization ID.
dataThe entity snapshot (the contact, conversation or flow response).

Verifying the signature

Every delivery carries an X-Baat-Signature header so you can confirm the request is authentic and untampered. The value is an HMAC-SHA256 of the raw request body, keyed with your signing secret, hex-encoded and prefixed with sha256=:

X-Baat-Signature: sha256=4f1e2d…

To verify, compute the same HMAC over the raw body and compare. Node.js example:

const crypto = require("crypto");

// Use the raw, unparsed request body (e.g. express.raw())
function verifyBaatSignature(rawBody, headerValue, signingSecret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", signingSecret)
          .update(rawBody, "utf8")
          .digest("hex");
  // constant-time compare
  const a = Buffer.from(headerValue || "");
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/webhooks/baat", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.header("X-Baat-Signature");
  if (!verifyBaatSignature(req.body, sig, process.env.BAAT_WEBHOOK_SECRET)) {
    return res.status(401).send("bad signature");
  }
  const event = JSON.parse(req.body.toString("utf8"));
  // …handle event…
  res.sendStatus(200);
});

Compute the HMAC over the exact bytes Baat sent. If your framework re-serializes the JSON before you hash it, whitespace or key-order differences will break the comparison — always hash the raw body.

Responding & retries

Return a 2xx status quickly to acknowledge receipt. If your endpoint errors or times out, Baat retries with an increasing backoff — up to 8 attempts:

AttemptRoughly after
1immediately
210 minutes
31 hour
46 hours
512 hours
624 hours
74 days
87 days

After the final failed attempt the delivery is marked Failed. Because an event can be delivered more than once, make your handler idempotent (de-duplicate on the entity ID plus occurred_at).

Inspecting deliveries — Logs & usage

The Logs & usage tab records every delivery attempt so you can debug integrations without adding logging on your side.

ColumnMeaning
EventWhich event fired.
EndpointThe URL Baat called.
StatusSuccess, Failed, or Pending (awaiting a retry).
AttemptsHow many delivery attempts have been made.
ErrorThe last error returned by your endpoint, if any.
Fired atWhen the most recent attempt was made.

Enabling, disabling & deleting

Use the menu on a webhook row to Disable it (Baat stops sending events but keeps the configuration and secret) or Delete it permanently. Re-enable a disabled webhook from the same menu.

Need a hand?

Our team answers on WhatsApp, usually within a business day.

Contact support Book a demo