npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@srinathh/openclaw-channel-twilio-whatsapp

v2.0.10

Published

Twilio WhatsApp channel plugin for OpenClaw

Readme

OpenClaw Twilio WhatsApp Channel

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:

| 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

This plugin is loaded by OpenClaw at runtime via npm. Add it to your OpenClawInstance CRD:

apiVersion: openclaw.rocks/v1alpha1
kind: OpenClawInstance
metadata:
  name: openclaw
spec:
  plugins:
    - "@srinathh/openclaw-channel-twilio-whatsapp@latest"

Or in a non-Kubernetes deployment, install it into your OpenClaw runtime's node_modules:

npm install @srinathh/openclaw-channel-twilio-whatsapp@latest

Then add it to the plugins.load.paths array in openclaw.json (see Configuration).

Configuration

openclaw.json

{
  "channels": {
    "twilio-whatsapp": {
      "enabled": true,
      "dmPolicy": "allowlist",
      "allowFrom": ["+14155551234", "+14155555678"],
      "fromNumber": "+14155550000",
      "webhookUrl": "https://your-public-host.example.com"
    }
  },
  "plugins": {
    "enabled": true,
    "allow": ["@srinathh/openclaw-channel-twilio-whatsapp"],
    "load": {
      "paths": ["~/.openclaw/node_modules/@srinathh/openclaw-channel-twilio-whatsapp"]
    },
    "entries": {
      "@srinathh/openclaw-channel-twilio-whatsapp": { "enabled": true }
    }
  }
}

| 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 |

All phone numbers use E.164 format without the whatsapp: prefix — the plugin prepends it internally when calling Twilio.

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 / 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: requires openclaw >= 2026.3.28 (uses the plugin-sdk/* subpath imports)
  • 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.