Twilio WhatsApp Channel

Twilio WhatsApp channel plugin for OpenClaw

Install

openclaw plugins install clawhub:@srinathh/openclaw-channel-twilio-whatsapp

OpenClaw 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.md and 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.

npm version License: Apache-2.0

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:

ConcernBaileysTwilio (this plugin)
Protocol stabilityBreaks when WhatsApp changes their internal protocolOfficial, versioned API
Account safetyRisk of bans for "automated" behaviorCompliant Business API
Delivery receiptsBest-effortFirst-class status callbacks
Group messagingYesNo (1:1 DMs only)
CostFreePer-message fees
SetupQR-code pairingSender 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.jsonchannels.twilio-whatsapp

FieldRequiredDescription
enabledyesActivate the channel
dmPolicyyes"allowlist" (only allowFrom numbers) or "open" (anyone)
allowFromwhen allowlistPhone numbers in E.164 format (e.g. +14155551234)
fromNumberyesYour Twilio WhatsApp sender in E.164
webhookUrlyesPublic base URL where Twilio can reach OpenClaw — used both for signature validation and media serving
textChunkLimitno (default 1600)Max characters per outbound message before splitting (Twilio rejects > 1600 with error 21617)
chunkModeno (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)

VariableRequiredDescription
TWILIO_ACCOUNT_SIDyesYour Twilio account SID (starts with AC)
TWILIO_AUTH_TOKENyesYour 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

PathAuthPurpose
POST /webhook/twilio-whatsappplugin (signature-validated)Inbound from Twilio
GET /webhook/twilio-whatsapp/media/*pluginServes outbound media for Twilio to fetch
GET /webhook/twilio-whatsapp/healthpluginLiveness 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 / MediaPaths envelope 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

  1. Twilio POSTs application/x-www-form-urlencoded body with Body, From, MessageSid, NumMedia, etc.
  2. Plugin validates X-Twilio-Signature against webhookUrl + path — rejects with 403 on mismatch
  3. Plugin checks From against allowFrom (with whatsapp: prefix stripped) — rejects with 403 if not allowed
  4. Plugin immediately responds with empty TwiML (<Response/>) so Twilio doesn't time out
  5. Plugin downloads any inbound media (async, after responding)
  6. Plugin calls dispatchInboundDirectDmWithRuntime with the message envelope
  7. 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 the plugin-sdk/* subpath imports were introduced), but earlier 2026.x gateways have a core-side EACCES 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.