Skip to content

clawSean/openclaw-twilio-sms

Repository files navigation

OpenClaw Twilio SMS

Twilio SMS connects OpenClaw to carrier SMS through Twilio Programmable Messaging.

This is an external OpenClaw channel plugin. It is intentionally packaged for the ClawHub/community plugin path rather than as a bundled OpenClaw core PR.

Outbound text sends use the shared OpenClaw message delivery path and durable receipts. Inbound SMS webhooks verify Twilio signatures, reject replays, use bounded request bodies, and default to pairing-first sender authorization before model turns run.

Native SMS alignment

This repository is the external/ClawHub path for Twilio SMS. It is also prior art and proof support for OpenClaw's native SMS direction:

The goal is not to compete with a native OpenClaw sms channel. If native SMS lands, this plugin remains useful as an installable external option, a security/proof reference, and a compatibility path for deployments that want a provider-specific twilio-sms channel.

Areas this plugin can help validate upstream:

  • pairing-first sender admission
  • Twilio signature verification and replay handling
  • bounded webhook bodies and fail-closed auth behavior
  • SMS-safe Markdown flattening and chunking
  • durable receipts carrying Twilio Message SIDs
  • redacted live Twilio inbound/outbound proof from a real A2P setup

Install

ClawHub package publishing is the intended distribution path:

openclaw plugins install clawhub:clawsean/openclaw-twilio-sms

Until the ClawHub package is published, install from a local checkout:

git clone https://github.com/clawSean/openclaw-twilio-sms.git
cd openclaw-twilio-sms
npm install
npm run build
openclaw plugins install "$(pwd)"

Gateway/plugin reloads are required after installing or changing plugin code. Do not rely on a config hot reload for source-code changes.

Configure

Minimal config:

{
  channels: {
    "twilio-sms": {
      enabled: true,
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: "TWILIO_AUTH_TOKEN",
      fromNumber: "+15551230000",
      publicUrl: "https://sms.example.com/twilio-sms/webhook",
      dmPolicy: "pairing",
    },
  },
}

Environment variables for the default account:

  • TWILIO_ACCOUNT_SID
  • TWILIO_AUTH_TOKEN
  • TWILIO_SMS_FROM
  • TWILIO_MESSAGING_SERVICE_SID

Configure the Twilio Messaging webhook URL to:

https://sms.example.com/twilio-sms/webhook

Set channels.twilio-sms.publicUrl to the same public URL when OpenClaw is behind a reverse proxy. Signature verification uses publicUrl as the trusted origin and the incoming request path/query as the signed webhook URL. Without publicUrl, the plugin uses the direct Host header and does not trust forwarded host headers.

Proxy safety: set publicUrl in production whenever Twilio reaches OpenClaw through a proxy, tunnel, or load balancer. Leaving it unset is intended for direct/local deployments where the incoming Host header is already the URL Twilio signed.

You can use a Messaging Service instead of a sender number:

{
  channels: {
    "twilio-sms": {
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: "TWILIO_AUTH_TOKEN",
      messagingServiceSid: "MGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    },
  },
}

Multiple accounts:

{
  channels: {
    "twilio-sms": {
      defaultAccount: "alerts",
      accounts: {
        alerts: {
          accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
          authToken: "TWILIO_AUTH_TOKEN",
          fromNumber: "+15551230000",
        },
      },
    },
  },
}

Send messages

Use the normal message delivery surface. Targets can be bare E.164 numbers when the channel is explicit:

openclaw message send --channel twilio-sms --target +15551230001 --message "Hello"

Provider-prefixed targets are also accepted:

openclaw message send --target twilio:+15551230001 --message "Hello"

twilio: is the provider prefix. The generic sms: prefix is not used by this plugin because other channels use it as an internal service selector.

Access control

Direct messages default to pairing:

{
  channels: {
    "twilio-sms": {
      dmPolicy: "pairing",
      allowFrom: ["+15551230001"],
    },
  },
}

Policies:

  • pairing: unknown senders must be approved before they can reach an agent.
  • allowlist: only allowFrom numbers can reach the agent.
  • open: every sender is allowed and requires allowFrom: ["*"].
  • disabled: inbound direct messages are blocked.

SMS is cost-bearing and phone numbers are personal data. Prefer pairing or allowlist unless you intentionally want public inbound SMS.

Message behavior

  • SMS is text-only in the MVP.
  • Groups, reactions, edits, polls, typing indicators, and threads are not supported.
  • Outbound Markdown is flattened to plain text before sending.
  • Long messages are chunked before delivery. The default chunk limit is 1530 characters, and channels.twilio-sms.textChunkLimit can reduce it.
  • Durable receipts include Twilio Message SIDs.

Inbound webhook direction

Inbound Twilio webhooks are handled by the gateway route at the configured webhook path, defaulting to /twilio-sms/webhook.

The inbound path:

  • validates X-Twilio-Signature against the configured Account SID/Auth Token
  • rejects replayed MessageSid/SmsSid deliveries without dispatching twice
  • acknowledges valid webhooks before the agent turn runs
  • gates unknown direct senders through pairing by default
  • dispatches accepted inbound SMS through the shared channel turn kernel
  • sends final assistant replies back through durable Twilio SMS delivery

Keep dmPolicy as pairing or allowlist unless you explicitly want public inbound SMS. The channel remains text-only; MMS/media is deferred.

Replay protection currently uses an in-process cache. That is enough for a single Gateway process, but clustered or multi-replica deployments should put Twilio webhooks behind sticky routing or add a shared replay store before exposing high-volume traffic.

Known limitations

  • Replay protection is process-local. Use a single Gateway process, sticky routing, or a shared replay store before exposing clustered/high-volume SMS traffic.
  • The MVP is SMS text-only. MMS/media, groups, reactions, edits, polls, typing indicators, and threads are intentionally out of scope.
  • A redacted live proof bundle is still required before treating the package as production-ready or asking reviewers to bless the ClawHub listing.

See PROOF_PLAN.md for the redacted live-proof checklist.

Prior Art

See EXISTING_WORK.md for the ClawHub/GitHub redundancy review. The short version: there are several public Twilio SMS attempts, but no ClawHub-listed first-class OpenClaw channel plugin was found. This package is shaped to avoid repeating the prior core PR path and to address known review notes around fail-closed webhook auth, replay protection, rate/in-flight control, and plain-SMS formatting.

This work also connects to the later native-SMS effort in openclaw/openclaw#88476. The preferred outcome is a polished first-class OpenClaw SMS experience, with this repository preserving the external plugin path and implementation trail.

About

External OpenClaw Twilio SMS channel plugin

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors