Channels

WhatsApp

Meta Cloud API JSON webhook signed with X-Hub-Signature-256. HMAC fail-closes without app_secret. Subscribe handshake is GET hub.mode=subscribe on the same HTTP front.

Self-host

In Meta Developer Console, add WhatsApp, copy the access token, phone number ID, and app secret, set a verify token, point the callback at a public HTTPS URL, subscribe the messages field.

export WHATSAPP_ACCESS_TOKEN='…'
export WHATSAPP_PHONE_NUMBER_ID='…'
export WHATSAPP_APP_SECRET='…'
export WHATSAPP_VERIFY_TOKEN='…'
export PORT=8080
cx.channels.add(
    "whatsapp",
    via="self-host",
    access_token=access_token,
    phone_number_id=phone_number_id,
    app_secret=app_secret,
    bot_token="local",
)
# POST -> cx.handle("whatsapp", body, headers)
# GET hub.mode=subscribe on the same HTTP front (not handle())
await cx.channels.add("whatsapp", {
  via: "self-host",
  access_token,
  phone_number_id,
  app_secret,
  bot_token: "local",
})
// POST → await cx.handle("whatsapp", body, headers)
// GET hub.mode=subscribe on the same HTTP front (not handle())

What it can do

Plans Post (including a button menu), Reply, SendMedia, and React. No pin, typing, edit, or delete. Delivery receipts are not core Events — parse returns [].