/webhooks/sms), validates Twilio request signatures by default, and sends replies back through Twilio’s Messages API.
Status: official plugin, installed separately. Text only: no MMS/media, direct messages only.
Pairing
Default DM policy for SMS is pairing.
Gateway security
Review webhook exposure and sender access controls.
Channel troubleshooting
Cross-channel diagnostics and repair playbooks.
Before you begin
You need:- The official SMS plugin installed with
openclaw plugins install @openclaw/sms. - A Twilio account with an SMS-capable phone number, or a Twilio Messaging Service.
- The Twilio Account SID and Auth Token.
- A public HTTPS URL that reaches your OpenClaw Gateway.
- A sender policy choice:
pairing(default) for private use,allowlistfor preapproved phone numbers, oropenonly for intentionally public SMS access.
Quick Setup
1
Install the plugin
2
Create or choose a Twilio sender
In Twilio, open Phone Numbers > Manage > Active numbers and choose an SMS-capable number. Save:
- Account SID, for example
ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - Auth Token
- Sender phone number, for example
+15551234567
MGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.3
Configure the SMS channel
Save this as Apply it:
sms.patch.json5 and change the placeholders:4
Point Twilio at the Gateway webhook
In the Twilio phone number settings, open Messaging and set A message comes in to:Use HTTP
POST. The default local path is /webhooks/sms; change channels.sms.webhookPath if you need a different route.5
Expose the exact SMS webhook path
Your public URL must route the SMS path to the Gateway process (default port Voice Call and SMS use separate webhook paths. If the same Twilio number handles both, keep both routes configured in Twilio and in your tunnel.
18789). If you use Tailscale Funnel for local testing, expose /webhooks/sms explicitly:6
Start the Gateway and approve first sender
Configuration Examples
All keys live underchannels.sms (and per account under channels.sms.accounts.<id>):
Config file
Use config-file setup when you want the channel definition to travel with the Gateway config:Environment variables
Environment variables apply to the default account only; config values take precedence over env values.SecretRef auth token
authToken can be a SecretRef (source: "env" | "file" | "exec"). Use this when the Gateway should resolve the Twilio Auth Token from the OpenClaw secrets runtime instead of storing plaintext config:
Messaging Service sender
UsemessagingServiceSid instead of fromNumber when Twilio should choose the sender through a Messaging Service:
fromNumber and messagingServiceSid are present after config and env resolution, fromNumber is used.
Default outbound target
SetdefaultTo when automation or agent-initiated delivery should have a default destination if a send flow omits an explicit target:
Access control
channels.sms.dmPolicy controls direct SMS access:
pairing(default): unknown senders get a pairing code; approve withopenclaw pairing approve sms <CODE>.allowlist: only senders inallowFromare processed. An emptyallowFromrejects every sender (the Gateway logs a startup warning).open: config validation requiresallowFromto include"*". Without the wildcard, only listed numbers can chat.disabled: all inbound DMs are dropped.
allowFrom entries should be E.164 phone numbers such as +15551234567. sms: and twilio-sms: prefixes are accepted and normalized. For a private assistant, prefer dmPolicy: "allowlist" with explicit phone numbers:
Sending SMS
With the SMS channel selected, targets accept bare E.164 numbers or thesms: prefix:
twilio-sms: prefix selects this channel without taking over the sms: service prefix, which iMessage uses to pick carrier SMS delivery for its own targets:
--target. defaultTo is for automation and agent-initiated delivery paths where the target can be resolved from channel config.
Agent replies from inbound SMS conversations automatically go back to the sender through the configured Twilio sender.
SMS output is plain text. OpenClaw strips markdown, flattens fenced code blocks, rewrites links as label (url), and splits long replies into chunks of at most textChunkLimit characters (default 1500) before sending them through Twilio.
Verify Setup
After the Gateway starts:- Confirm the Gateway log shows the SMS webhook route.
- Run a Twilio-side probe (checks the configured Twilio webhook URL/method and recent inbound errors):
- Send an SMS to the Twilio number from your phone.
- Run
openclaw pairing list sms. - Approve the pairing code with
openclaw pairing approve sms <CODE>. - Send another SMS and confirm the agent replies.
End-to-end test from macOS iMessage/SMS
On a Mac that can send carrier SMS through Messages, you can useimsg to drive the sender side without touching your phone:
Webhook security
By default, OpenClaw validatesX-Twilio-Signature using publicWebhookUrl and authToken. Keep the endpoint portion of publicWebhookUrl byte-for-byte aligned with the URL configured in Twilio, including scheme, host, path, and query string. OpenClaw excludes Twilio connection-override fragments (#...) from signature computation, as Twilio requires.
The webhook route also enforces, independent of signature validation:
POSTonly.- Failed-request budget of 300 requests per minute per SMS account, webhook route, and resolved client address. All requests count toward this budget, but HTTP 429 is applied only after a request fails body parsing, Twilio validation, or AccountSid matching.
- Dispatchable callback rate limit of 30 accepted callbacks per minute per SMS account, webhook route, and resolved client address after those checks pass (HTTP 429 above that). If signature validation is disabled, this 30/min limit is the unauthenticated dispatch cap.
- Client addresses are resolved through the shared Gateway trusted-proxy rules. If
gateway.trustedProxiescontains the reverse proxy that forwards Twilio callbacks, OpenClaw keys these limits from the forwarded client address; otherwise it falls back to the direct socket address. - The payload
AccountSidmust match the configuredaccountSid(HTTP 403 otherwise). - Replayed
MessageSidvalues are deduplicated for 10 minutes. - Each SMS account’s replay cache retains up to 10,000 live message SIDs. When every slot is live, new webhooks for that account fail closed with HTTP 429 and a
Retry-Afterheader until the oldest slot expires. - Request bodies over 32 KB are rejected.
Retry-After. The #rp=4xx and #rp=all connection overrides opt into 4xx retries, but Twilio caps the complete retry transaction at 15 seconds, so retries can still finish before a replay-cache slot expires. Configure a fallback URL when another handler must receive failed deliveries; treat a 429 as a fail-closed rejection, not reliable backpressure.
For local tunnel testing only, you can set:
Multi-account config
Useaccounts when you operate more than one Twilio number:
webhookPath; the Gateway refuses to register a webhook route whose path is already owned by another account. TWILIO_*/SMS_* environment fallbacks apply only to the default account; set defaultAccount to change which account that is.
Troubleshooting
Twilio returns 403 or OpenClaw rejects the webhook
Check thatpublicWebhookUrl exactly matches the URL configured in Twilio, including scheme, host, path, and query string. Twilio signs the public URL string, so proxy rewrites and alternate hostnames can break signature validation.
A 403 with Invalid account means the inbound payload’s AccountSid does not match the configured accountSid; check that the webhook points at the account that owns the number.
No pairing request appears
Check the Twilio number’s Messaging webhook URL and method. It must point to the SMS webhook URL and usePOST. Also confirm the Gateway is reachable from the public internet or through your tunnel.
If the Twilio message log shows error 11200, Twilio accepted the inbound SMS but could not reach your webhook. Check:
- Twilio Messaging > A message comes in points at
publicWebhookUrl. - The method is
POST. - The tunnel or reverse proxy exposes the exact
webhookPath; for Tailscale Funnel, runtailscale funnel statusand confirm/webhooks/smsis listed. publicWebhookUrluses the same scheme, host, path, and query string Twilio sends, so signature validation can reproduce the signed URL.
openclaw channels status --channel sms --probe surfaces both mismatched Twilio webhook settings and recent 11200 errors.
Outbound sends fail
ConfirmaccountSid, authToken, and either fromNumber or messagingServiceSid are resolved. If you use a trial Twilio account, the destination number may need to be verified in Twilio before outbound SMS will send.
Messages arrive but the agent does not answer
CheckdmPolicy and allowFrom. With the default pairing policy, the sender must be approved before normal agent turns are processed.