Claude
Skills
Sign in
Back

twilio-sms

Included with Lifetime
$97 forever

SMS/MMS: send/receive, TwiML, webhooks, delivery receipts, opt-out, A2P 10DLC, short codes

Generalsmsmmstwiliomessaging

What this skill does


# twilio-sms

## Purpose

Enable OpenClaw to implement and operate Twilio Programmable Messaging (SMS/MMS) in production:

- Send SMS/MMS reliably (Messaging Services, geo-matching, sticky sender, media constraints).
- Receive inbound messages via webhooks and respond with TwiML.
- Track delivery lifecycle via status callbacks (queued/sent/delivered/undelivered/failed).
- Implement opt-out/STOP compliance and keyword workflows.
- Operate A2P 10DLC (US long code) and toll-free verification constraints.
- Debug and harden: signature validation, retries, idempotency, rate limits, carrier errors.

This skill is for engineers building messaging pipelines, customer notifications, 2-way support, and compliance-sensitive messaging.

---

## Prerequisites

### Accounts & Twilio Console setup

- Twilio account with **Programmable Messaging** enabled.
- At least one of:
  - **Messaging Service** (recommended) with sender pool (long codes / toll-free / short code).
  - A dedicated **Phone Number** capable of SMS/MMS.
- For US A2P 10DLC:
  - Brand + Campaign registration completed in Twilio Console (Messaging → Regulatory Compliance / A2P 10DLC).
- For toll-free:
  - Toll-free verification submitted/approved if sending high volume to US/CA.

### Runtime versions (tested)

- Node.js **20.11.1** (LTS) + npm **10.2.4**
- Python **3.11.7**
- Twilio SDKs:
  - `twilio` (Node) **4.23.0**
  - `twilio` (Python) **9.4.1**
- Web framework examples:
  - Express **4.18.3**
  - FastAPI **0.109.2** + Uvicorn **0.27.1**
- Optional tooling:
  - Twilio CLI **5.16.0**
  - ngrok **3.13.1** (local webhook tunneling)
  - Docker **25.0.3** + Compose v2 **2.24.6**

### Credentials & auth

You need:

- `TWILIO_ACCOUNT_SID` (starts with `AC...`)
- `TWILIO_AUTH_TOKEN`
- One of:
  - `TWILIO_MESSAGING_SERVICE_SID` (starts with `MG...`) **preferred**
  - `TWILIO_FROM_NUMBER` (E.164, e.g. `+14155552671`)

Store secrets in a secret manager (AWS Secrets Manager / GCP Secret Manager / Vault). For local dev, `.env` is acceptable.

### Network & webhook requirements

- Public HTTPS endpoint for inbound and status callbacks.
- Must accept `application/x-www-form-urlencoded` (Twilio default) and/or JSON depending on endpoint.
- Validate Twilio signatures (`X-Twilio-Signature`) on inbound webhooks.

---

## Core Concepts

### Programmable Messaging objects

- **Message**: a single outbound or inbound SMS/MMS. Identified by `MessageSid` (`SM...`).
- **Messaging Service**: abstraction over senders; supports:
  - sender pool
  - geo-matching
  - sticky sender
  - smart encoding
  - status callback configuration
- **Status Callback**: webhook invoked as message state changes.
- **Inbound Webhook**: webhook invoked when Twilio receives an inbound message to your number/service.

### Delivery lifecycle (practical)

Typical `MessageStatus` values you will see:

- `queued` → `sending` → `sent` → `delivered`
- Failure paths:
  - `undelivered` (carrier rejected / unreachable)
  - `failed` (Twilio could not send; configuration/auth issues)

Treat `sent` as “handed to carrier”, not “delivered”.

### TwiML for Messaging

Inbound SMS/MMS webhooks can respond with TwiML:

```xml
<Response>
  <Message>Thanks. We received your message.</Message>
</Response>
```

Use TwiML for synchronous replies; use REST API for async workflows.

### Opt-out compliance

- Twilio automatically handles standard opt-out keywords (e.g., `STOP`, `UNSUBSCRIBE`).
- When a user opts out, Twilio blocks further messages from that sender/service to that recipient until they opt back in (`START`).
- Your app should:
  - treat opt-out as a first-class state
  - avoid retry storms on blocked recipients
  - log and suppress sends to opted-out numbers

### A2P 10DLC / short codes / toll-free

- **US A2P 10DLC**: required for application-to-person messaging over US long codes at scale. Unregistered traffic may be filtered or blocked.
- **Short codes**: high throughput, expensive, long provisioning.
- **Toll-free**: good for US/CA; verification improves deliverability and throughput.

### Webhook retries and idempotency

Twilio retries webhooks on non-2xx responses. Your webhook handlers must be:

- idempotent (dedupe by `MessageSid` / `SmsSid`)
- fast (respond quickly; enqueue work)
- resilient (return 2xx once accepted)

---

## Installation & Setup

### Official Python SDK — Messaging

**Repository:** https://github.com/twilio/twilio-python  
**PyPI:** `pip install twilio` · **Supported:** Python 3.7–3.13

```python
from twilio.rest import Client
client = Client()  # TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN from env

# Send SMS
msg = client.messages.create(
    body="Hello from Python!",
    from_="+15017250604",
    to="+15558675309"
)
print(msg.sid)

# List recent messages
for m in client.messages.list(limit=20):
    print(m.body, m.status)
```

Source: [twilio/twilio-python — messages](https://github.com/twilio/twilio-python/blob/main/twilio/rest/api/v2010/account/message/__init__.py)

### Ubuntu 22.04 (x86_64 / ARM64)

```bash
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg jq
```

Node.js 20 via NodeSource:

```bash
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v   # v20.11.1 (or later 20.x)
npm -v    # 10.2.4 (or later)
```

Python 3.11:

```bash
sudo apt-get install -y python3.11 python3.11-venv python3-pip
python3.11 --version
```

Twilio CLI 5.16.0:

```bash
npm install -g [email protected]
twilio --version
```

ngrok 3.13.1 (optional):

```bash
curl -fsSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/ngrok.gpg
echo "deb [signed-by=/usr/share/keyrings/ngrok.gpg] https://ngrok-agent.s3.amazonaws.com buster main" \
  | sudo tee /etc/apt/sources.list.d/ngrok.list
sudo apt-get update && sudo apt-get install -y ngrok
ngrok version
```

### Fedora 39 (x86_64 / ARM64)

```bash
sudo dnf install -y curl jq nodejs python3.11 python3.11-pip
node -v
python3.11 --version
```

Twilio CLI:

```bash
sudo npm install -g [email protected]
twilio --version
```

### macOS (Intel + Apple Silicon)

Homebrew:

```bash
brew update
brew install node@20 [email protected] jq
```

Ensure PATH:

```bash
echo 'export PATH="/opt/homebrew/opt/node@20/bin:/opt/homebrew/opt/[email protected]/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
node -v
python3.11 --version
```

Twilio CLI:

```bash
npm install -g [email protected]
twilio --version
```

ngrok:

```bash
brew install ngrok/ngrok/ngrok
ngrok version
```

### Docker (all platforms)

```bash
docker --version
docker compose version
```

### Twilio CLI authentication

Interactive login:

```bash
twilio login
```

Or set env vars (CI):

```bash
export TWILIO_ACCOUNT_SID="YOUR_ACCOUNT_SID"
export TWILIO_AUTH_TOKEN="your_auth_token"
```

Verify:

```bash
twilio api:core:accounts:fetch --sid "$TWILIO_ACCOUNT_SID"
```

### Local webhook tunneling (ngrok)

```bash
ngrok http 3000
# note the https forwarding URL, e.g. https://f3a1-203-0-113-10.ngrok-free.app
```

Configure Twilio inbound webhook to:

- `https://.../twilio/inbound`
- Status callback to:
  - `https://.../twilio/status`

---

## Key Capabilities

### Send SMS/MMS (REST API)

- Use Messaging Service (`messagingServiceSid`) for production.
- Use `statusCallback` for delivery receipts.
- Use `provideFeedback=true` for carrier feedback (where supported).

Node (SMS):

```javascript
import twilio from "twilio";

const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);

const msg = await client.messages.create({
  messagingServiceSid: process.env.TWILIO_MESSAGING_SERVICE_SID,
  to: "+14155550123",
  body: "Build 742 deployed. Reply STOP to opt out.",
  statusCallback: "https://api.example.com/twilio/status",
  provideFeedback: true,
});

console.log(msg.sid, msg.status);
```

Python (MMS):

```python
from twilio.rest import Client
import os

client = Client(os.environ["TWILIO_ACCOUNT_SID"], os.environ["TWILIO_AUTH_TOKEN"])

msg = cl

Related in General