Twilio WhatsApp Channel
Twilio WhatsApp channel plugin for OpenClaw
Install
openclaw plugins install clawhub:@srinathh/openclaw-channel-twilio-whatsappOpenClaw Twilio WhatsApp Channel
⚠️ Install via a coding agent — not via the standard OpenClaw install flow. This plugin is non-trivial to deploy: it requires a Twilio account, a public HTTPS URL, environment-variable secrets, exact webhook-URL matching, and gateway version
>= 2026.5.26. The ClawHub one-click install will leave you with a half-configured plugin that silently 403s or 404s.Preferred path: point a coding agent (Claude Code, Cursor, etc.) at
AGENT_INSTRUCTIONS.mdand have it walk you through setup. The ClawHub listing exists for discoverability — not as a supported install path.
A channel plugin for OpenClaw that connects your AI agent to WhatsApp via the Twilio Business API.
Why Twilio over Baileys?
OpenClaw ships with a built-in WhatsApp channel based on Baileys, which reverse-engineers the WhatsApp Web protocol. Baileys is convenient — no business verification, no monthly fees — but the trade-offs are real:
| Concern | Baileys | Twilio (this plugin) |
|---|---|---|
| Protocol stability | Breaks when WhatsApp changes their internal protocol | Official, versioned API |
| Account safety | Risk of bans for "automated" behavior | Compliant Business API |
| Delivery receipts | Best-effort | First-class status callbacks |
| Group messaging | Yes | No (1:1 DMs only) |
| Cost | Free | Per-message fees |
| Setup | QR-code pairing | Sender registration + webhook |
Pick this plugin when you need stability and compliance — for personal automations or when you need group chat, the bundled Baileys channel is simpler.
Features
- Inbound webhooks via OpenClaw's gateway (no separate HTTP server)
- Twilio signature validation on every inbound request
- Allowlist enforcement so only approved phone numbers can talk to your agent
- Inbound media download with redirect-following Basic Auth
- Outbound media staging — local files are served back to Twilio via UUID-randomized URLs
- Message chunking at Twilio's 1600-char limit
- WhatsApp formatting hints injected into the agent prompt (
*bold*,_italic_, etc.) - Fire-and-forget webhook responses — TwiML returned immediately, processing happens async (avoids Twilio's 15s timeout)
Installation
See AGENT_INSTRUCTIONS.md. Point a coding agent at it and have it walk you through the install — Twilio sender setup, public webhook URL, gateway-side plugin install, openclaw.json config, env-var secrets, and verification. The agent will collect the inputs from you, generate the right config for your deployment shape (Docker / Compose / k8s), and avoid the common foot-guns (legacy config shape, wrong container UID, etc.).
The standard ClawHub one-click install is not sufficient for this plugin — the listing exists for discoverability. The plugin needs out-of-band configuration that ClawHub doesn't collect.
Configuration reference
The agent install will write these for you — this section is for reference only.
openclaw.json — channels.twilio-whatsapp
| Field | Required | Description |
|---|---|---|
enabled | yes | Activate the channel |
dmPolicy | yes | "allowlist" (only allowFrom numbers) or "open" (anyone) |
allowFrom | when allowlist | Phone numbers in E.164 format (e.g. +14155551234) |
fromNumber | yes | Your Twilio WhatsApp sender in E.164 |
webhookUrl | yes | Public base URL where Twilio can reach OpenClaw — used both for signature validation and media serving |
textChunkLimit | no (default 1600) | Max characters per outbound message before splitting (Twilio rejects > 1600 with error 21617) |
chunkMode | no (default length) | "length" or "newline" — prefer paragraph boundaries when splitting |
All phone numbers use E.164 format without the whatsapp: prefix — the plugin prepends it internally when calling Twilio.
Modern OpenClaw gateways key plugin config by the manifest id twilio-whatsapp (not the npm package name) in plugins.allow / plugins.entries. The legacy plugins.load.paths field is no longer used — plugin install paths are auto-discovered. See AGENT_INSTRUCTIONS.md for the exact openclaw.json shape.
Environment variables (secrets)
| Variable | Required | Description |
|---|---|---|
TWILIO_ACCOUNT_SID | yes | Your Twilio account SID (starts with AC) |
TWILIO_AUTH_TOKEN | yes | Your Twilio auth token |
Twilio setup
1. Get a WhatsApp sender
For development, use the Twilio Sandbox for WhatsApp. For production, register a WhatsApp sender.
2. Configure the inbound webhook
In the Twilio Console for your WhatsApp sender, set:
- When a message comes in:
https://<your-host>/webhook/twilio-whatsapp - Method:
HTTP POST
The path is fixed by this plugin. The host must match webhookUrl in your OpenClaw config exactly — Twilio's signature validation requires the URL to match.
3. Verify the health endpoint
curl https://<your-host>/webhook/twilio-whatsapp/health
# {"status":"ok","channel":"twilio-whatsapp"}
4. Send a test message
WhatsApp the number you registered in fromNumber from a phone in your allowFrom list. The agent should reply.
Architecture
┌─────────────────┐ POST /webhook/twilio-whatsapp
│ Twilio API │ ──────────────────────────────────► ┌──────────────────┐
│ │ ◄────────── 200 TwiML <Response/> ── │ OpenClaw gateway │
└─────────────────┘ │ (this plugin) │
▲ └────────┬─────────┘
│ client.messages.create({...}) │ dispatchInboundDirectDmWithRuntime
│ ▼
┌───────┴─────────┐ ┌──────────────┐
│ Outbound: │ ◄──────────── deliver(payload) ────── │ Agent runtime│
│ sendText / │ └──────────────┘
│ sendMedia │
└─────────────────┘
HTTP routes registered
| Path | Auth | Purpose |
|---|---|---|
POST /webhook/twilio-whatsapp | plugin (signature-validated) | Inbound from Twilio |
GET /webhook/twilio-whatsapp/media/* | plugin | Serves outbound media for Twilio to fetch |
GET /webhook/twilio-whatsapp/health | plugin | Liveness check |
Media handling
Inbound media (Twilio → agent):
- Downloaded with redirect-following Basic Auth
- Saved to
~/.openclaw/media/twilio-whatsapp/inbound/<MessageSid>-<i><ext> - Path included in the
MediaPath/MediaPathsenvelope fields
Outbound media (agent → Twilio):
- Local files are copied to
~/.openclaw/media/twilio-whatsapp/outbound/<uuid><ext> - Served via the media endpoint with parent-directory check (no traversal)
- Twilio fetches the URL and forwards to WhatsApp
Inbound flow
- Twilio POSTs
application/x-www-form-urlencodedbody withBody,From,MessageSid,NumMedia, etc. - Plugin validates
X-Twilio-SignatureagainstwebhookUrl + path— rejects with403on mismatch - Plugin checks
FromagainstallowFrom(withwhatsapp:prefix stripped) — rejects with403if not allowed - Plugin immediately responds with empty TwiML (
<Response/>) so Twilio doesn't time out - Plugin downloads any inbound media (async, after responding)
- Plugin calls
dispatchInboundDirectDmWithRuntimewith the message envelope - Agent processes the message and sends a reply via
sendText/sendMedia
Development
git clone https://github.com/srinathh/openclaw-channel-twilio-whatsapp.git
cd openclaw-channel-twilio-whatsapp
npm install
npm run build
Project layout
src/
├── index.ts # defineChannelPluginEntry — plugin entry point
├── channel.ts # createChatChannelPlugin — main plugin definition
├── webhook.ts # Twilio webhook handler (signature validation + dispatch)
├── media.ts # download / stage / serve media
├── runtime.ts # createPluginRuntimeStore — runtime accessor for dispatch
├── util.ts # phone formatting + form body parsing
└── openclaw-sdk.d.ts # ambient type declarations for openclaw/plugin-sdk/*
Testing locally
You'll need an OpenClaw instance running with this plugin installed. The simplest setup:
# 1. In one terminal: build and link
npm run build
npm link
# 2. In your OpenClaw instance directory
npm link @srinathh/openclaw-channel-twilio-whatsapp
# 3. Add to your openclaw.json plugins config (see Configuration)
# 4. Use a tunnel (cloudflared, ngrok) to expose the gateway
# 5. Point Twilio's webhook at the tunnel URL
Compatibility
- OpenClaw gateway: requires
>= 2026.5.26. The plugin technically loads against>= 2026.3.28(when theplugin-sdk/*subpath imports were introduced), but earlier 2026.x gateways have a core-sideEACCES mkdir '/home/openclaw'bug that silently breaks outbound media — text replies arrive, images don't. - OpenClaw operator (k8s): requires v0.30.0+ for the plugin peerDependency symlink
- Node.js: 20+
Known limitations
- DMs only — no group chat (Twilio's WhatsApp Business API doesn't support groups)
- No reactions / typing indicators — Twilio doesn't expose these
- No threaded replies — WhatsApp threading not exposed by Twilio
- Single account — multiple Twilio accounts aren't supported in this version
License
Apache-2.0 — see LICENSE.
Contributing
Issues and PRs welcome at github.com/srinathh/openclaw-channel-twilio-whatsapp.
