Agent Native

twilio-conversations-classic-api

Build multi-channel messaging conversations using Twilio's classic API, combining SMS, WhatsApp, and web chat participants in persistent threads with message…

by TwilioOfficial publisherNot reviewed

Identity proven by GitHub's verified organisation badge (twilio)

Agents
Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode, claude.ai and API
License
MIT (permissive)
Pin
8aba46fpinned Oct 9, 2026
Context cost
about 4,200 tokenswhen the skill loads
GitHub stars
37on twilio/ai
Scripts
None found

What it does

“Build multi-channel messaging experiences using Twilio Conversations (classic) API. Covers creating conversations, adding participants (SMS, WhatsApp, chat), sending messages, and handling webhooks. Use this skill to manage persistent multi-party or multi-channel conversations beyond single-message SMS/WhatsApp.”
The author's description, from SKILL.md

Generated summary from the skill's own text

Build multi-channel messaging conversations using Twilio's classic API, combining SMS, WhatsApp, and web chat participants in persistent threads with message history. The skill covers creating conversations, adding participants across channels, sending messages with media support, and handling incoming webhooks to respond to events.

When to use it

  • Managing customer support conversations across multiple messaging channels
  • Maintaining conversation history with multiple participants over time
  • Adding media files to messages across SMS, WhatsApp, and chat
  • Tracking message delivery status and handling incoming messages via webhooks

When not to

  • Sending single SMS or WhatsApp messages without conversation context
  • New projects requiring enhanced features; use Conversations v2 API instead
  • Adding WhatsApp participants without an approved business account

Install

These commands install from the publisher's repository and need no account.

skills CLI

npx skills add twilio/ai --skill twilio-conversations-classic-api

Installs from the repository's default branch, which may have changed since the commit we checked.

GitHub CLI 2.90 or later

gh skill install twilio/ai twilio-conversations-classic-api@8aba46fb65dc8d9a20f4b301a68352064b4159a5

Installs the commit we checked (8aba46f).

Copy by hand

Download the folder at 8aba46f and put it in .claude/skills/twilio-conversations-classic-api for Claude Code and in .agents/skills/twilio-conversations-classic-api for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.

Skill folder on GitHub at 8aba46f

Claude Code plugin

/plugin install twilio-developer-kit@claude-plugins-official

The publisher's plugin in Claude's official marketplace. It may hold more than this skill, and we have not pinned it.

Copy for your agent

A prompt for any coding agent. It installs this skill from GitHub at the pinned commit, copies the files as they are, and runs nothing unless you ask.

Prompt

Install the agent skill "twilio-conversations-classic-api" by Twilio.

Source, pinned to commit 8aba46fb65dc8d9a20f4b301a68352064b4159a5:
https://github.com/twilio/ai/tree/8aba46fb65dc8d9a20f4b301a68352064b4159a5/skills/twilio/twilio-conversations-classic-api

1. Download that folder at exactly this commit. Do not use the default branch.
2. Copy every file unchanged, keeping the folder structure, into .claude/skills/twilio-conversations-classic-api/ for Claude Code and .agents/skills/twilio-conversations-classic-api/ for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode. Create the folders if they do not exist.
3. Do not edit the files, and do not run any script in the folder unless I ask you to.
4. When you are done, list the files you copied and where you put them.

Listing and checks: https://www.agentnative.dev/skills/twilio/twilio-conversations-classic-api

SKILL.md at the pin

---
name: twilio-conversations-classic-api
description: >
  Build multi-channel messaging experiences using Twilio Conversations (classic) API.
  Covers creating conversations, adding participants (SMS, WhatsApp, chat),
  sending messages, and handling webhooks. Use this skill to manage persistent
  multi-party or multi-channel conversations beyond single-message SMS/WhatsApp.
---

## Overview

Conversations (classic) API provides persistent, multi-channel threads where participants on SMS, WhatsApp, and web chat can message together. Unlike single-message APIs, Conversations maintains history and supports multi-agent access.

**Note:** This is the Conversations (classic) API (v1).

---

## Prerequisites

- Twilio account with Conversations (classic) enabled
  — New to Twilio? See `twilio-account-setup`
  — Enable at: [Console > Conversations > Manage > Overview](https://console.twilio.com/us1/develop/conversations/manage/overview) > **Enable Conversations**
- Environment variables:
  - `TWILIO_ACCOUNT_SID`
  - `TWILIO_AUTH_TOKEN`
  — See `twilio-iam-auth-setup` for credential setup and best practices
- SDK: `pip install twilio` / `npm install twilio`
- For SMS/WhatsApp participants: a Twilio number assigned to a Conversations Service

---

## Setup: Create a Conversation Service (classic)

A Conversation Service is the parent configuration container for all your conversations in the classic API. You need one before creating conversations with SMS/WhatsApp participants.

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

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

# Create a Conversation Service
service = client.conversations.v1.services.create(
    friendly_name="Customer Support Service"
)
print(f"Service SID: {service.sid}")
```

**Node.js**
```node
const twilio = require("twilio");
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);

// Create a Conversation Service
const service = await client.conversations.v1.services.create({
    friendlyName: "Customer Support Service"
});
console.log(`Service SID: ${service.sid}`);
```

**Next:** Assign your Twilio phone number to this service at [Console > Conversations > Manage > Services](https://console.twilio.com/us1/develop/conversations/manage/services) > Select your service > Add phone number.

---

## Quickstart

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

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

# Create a conversation (use default service or specify service_sid)
conversation = client.conversations.v1.conversations.create(
    friendly_name="Customer Support - Order #12345"
)

# Add an SMS participant
client.conversations.v1 \
    .conversations(conversation.sid) \
    .participants \
    .create(
        messaging_binding_address="+15558675310",
        messaging_binding_proxy_address="+15017122661"
    )

# Send a message
client.conversations.v1 \
    .conversations(conversation.sid) \
    .messages \
    .create(body="Hello! How can I help you today?", author="support-agent")
```

**Node.js**
```node
const twilio = require("twilio");
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);

// Create a conversation (use default service or specify serviceSid)
const conversation = await client.conversations.v1.conversations.create({
    friendlyName: "Customer Support - Order #12345",
});

// Add an SMS participant
await client.conversations.v1
    .conversations(conversation.sid)
    .participants.create({
        messagingBindingAddress: "+15558675310",
        messagingBindingProxyAddress: "+15017122661",
    });

// Send a message
await client.conversations.v1
    .conversations(conversation.sid)
    .messages.create({ body: "Hello! How can I help you today?", author: "support-agent" });
```

---

## Key Patterns

### Add Participants by Channel

**WhatsApp participant — Python**
```python
client.conversations.v1 \
    .conversations(conversation.sid) \
    .participants \
    .create(
        messaging_binding_address="whatsapp:+15558675310",
        messaging_binding_proxy_address="whatsapp:+14155238886"
    )
```

**WhatsApp participant — Node.js**
```node
await client.conversations.v1
    .conversations(conversationSid)
    .participants.create({
        messagingBindingAddress: "whatsapp:+15558675310",
        messagingBindingProxyAddress: "whatsapp:+14155238886",
    });
```

**Chat participant (web/mobile) — Python**
```python
client.conversations.v1 \
    .conversations(conversation.sid) \
    .participants \
    .create(identity="user-123")
```

**Chat participant (web/mobile) — Node.js**
```node
await client.conversations.v1
    .conversations(conversationSid)
    .participants.create({ identity: "user-123" });
```

### Send Media (All Channels)

**Python**
```python
# Send a message with media
client.conversations.v1 \
    .conversations(conversation.sid) \
    .messages \
    .create(
        body="Check out this image!",
        author="support-agent",
        media_url="https://example.com/image.jpg"
    )

# Multiple media URLs (up to 10)
client.conversations.v1 \
    .conversations(conversation.sid) \
    .messages \
    .create(
        body="Here are the documents",
        author="support-agent",
        media_url=[
            "https://example.com/doc1.pdf",
            "https://example.com/doc2.pdf"
        ]
    )
```

**Node.js**
```node
// Send a message with media
await client.conversations.v1
    .conversations(conversationSid)
    .messages.create({
        body: "Check out this image!",
        author: "support-agent",
        mediaUrl: "https://example.com/image.jpg"
    });

// Multiple media URLs (up to 10)
await client.conversations.v1
    .conversations(conversationSid)
    .messages.create({
        body: "Here are the documents",
        author: "support-agent",
        mediaUrl: [
            "https://example.com/doc1.pdf",
            "https://example.com/doc2.pdf"
        ]
    });
```

Media must be publicly accessible URLs. Supported: JPG, PNG, GIF, PDF, vCard. Max 10 URLs per message. Works across all channels: SMS (as MMS), WhatsApp, and chat participants all receive media.

### Add Multiple Participants

**Python**
```python
# Add multiple SMS participants to a conversation
participant_numbers = [
    "+15558675310",
    "+15558675311",
    "+15558675312"
]

twilio_number = "+15017122661"

for phone_number in participant_numbers:
    client.conversations.v1 \
        .conversations(conversation.sid) \
        .participants \
        .create(
            messaging_binding_address=phone_number,
            messaging_binding_proxy_address=twilio_number
        )
```

**Node.js**
```node
// Add multiple SMS participants to a conversation
const participantNumbers = [
    "+15558675310",
    "+15558675311",
    "+15558675312"
];

const twilioNumber = "+15017122661";

for (const phoneNumber of participantNumbers) {
    await client.conversations.v1
        .conversations(conversationSid)
        .participants.create({
            messagingBindingAddress: phoneNumber,
            messagingBindingProxyAddress: twilioNumber
        });
}
```

### Fetch Message History

**Python**
```python
# Get all messages from a conversation
messages = client.conversations.v1 \
    .conversations(conversation.sid) \
    .messages \
    .list(limit=50)

for message in messages:
    print(f"{message.author}: {message.body}")
```

**Node.js**
```node
// Get all messages from a conversation
const messages = await client.conversations.v1
    .conversations(conversationSid)
    .messages
    .list({ limit: 50 });

messages.forEach(message => {
    console.log(`${message.author}: ${message.body}`);
});
```

### List Conversations

**Python**
```python
# List all conversations
conversations = client.conversations.v1.conversations.list(limit=20)

for conv in conversations:
    print(f"{conv.friendly_name} - {conv.sid}")

# Filter by state
active_conversations = client.conversations.v1.conversations.list(
    state="active",
    limit=20
)
```

**Node.js**
```node
// List all conversations
const conversations = await client.conversations.v1.conversations.list({ limit: 20 });

conversations.forEach(conv => {
    console.log(`${conv.friendlyName} - ${conv.sid}`);
});

// Filter by state
const activeConversations = await client.conversations.v1.conversations.list({
    state: "active",
    limit: 20
});
```

### Remove Participants

**Python**
```python
# Remove a participant by participant SID
client.conversations.v1 \
    .conversations(conversation.sid) \
    .participants(participant_sid) \
    .delete()

# Find and remove by phone number
participants = client.conversations.v1 \
    .conversations(conversation.sid) \
    .participants \
    .list()

for p in participants:
    if p.messaging_binding and p.messaging_binding.get("address") == "+15558675310":
        client.conversations.v1 \
            .conversations(conversation.sid) \
            .participants(p.sid) \
            .delete()
```

**Node.js**
```node
// Remove a participant by participant SID
await client.conversations.v1
    .conversations(conversationSid)
    .participants(participantSid)
    .remove();

// Find and remove by phone number
const participants = await client.conversations.v1
    .conversations(conversationSid)
    .participants
    .list();

for (const p of participants) {
    if (p.messagingBinding?.address === "+15558675310") {
        await client.conversations.v1
            .conversations(conversationSid)
            .participants(p.sid)
            .remove();
    }
}
```

### Close/Complete Conversations

**Python**
```python
# Close a conversation (marks it inactive)
client.conversations.v1 \
    .conversations(conversation.sid) \
    .update(state="closed")

# Delete a conversation completely
client.conversations.v1 \
    .conversations(conversation.sid) \
    .delete()
```

**Node.js**
```node
// Close a conversation (marks it inactive)
await client.conversations.v1
    .conversations(conversationSid)
    .update({ state: "closed" });

// Delete a conversation completely
await client.conversations.v1
    .conversations(conversationSid)
    .remove();
```

### Handle Incoming Messages (Webhook)

Configure at Console > Conversations > Manage > Global Webhooks.

> **Security:** Always validate the `X-Twilio-Signature` header in production to confirm requests originate from Twilio. See `twilio-webhook-architecture` for validation patterns.

**Python (Flask)**
```python
from twilio.request_validator import RequestValidator

@app.route("/conversations/webhook", methods=["POST"])
def conversations_webhook():
    validator = RequestValidator(os.environ["TWILIO_AUTH_TOKEN"])
    if not validator.validate(request.url, request.form, request.headers.get("X-Twilio-Signature", "")):
        return "", 403

    event_type = request.form.get("EventType")
    conversation_sid = request.form.get("ConversationSid")
    author = request.form.get("Author")

    if event_type == "onMessageAdded" and author != "support-agent":
        client.conversations.v1.conversations(conversation_sid).messages.create(
            body="Thanks — an agent will be with you shortly.",
            author="support-bot"
        )
    return "", 204
```

**Node.js (Express)**
```node
app.post("/conversations/webhook", async (req, res) => {
    const valid = twilio.validateRequest(
        process.env.TWILIO_AUTH_TOKEN,
        req.headers["x-twilio-signature"],
        `https://${req.headers.host}${req.originalUrl}`,
        req.body
    );
    if (!valid) return res.status(403).send("Forbidden");

    const { EventType, ConversationSid, Author } = req.body;
    if (EventType === "onMessageAdded" && Author !== "support-agent") {
        await client.conversations.v1
            .conversations(ConversationSid)
            .messages.create({ body: "Thanks — an agent will be with you shortly.", author: "support-bot" });
    }
    res.sendStatus(204);
});
```

---

## Advanced Context

### Message Delivery Status

Track message delivery through webhooks. Configure at Console > Conversations > Manage > Global Webhooks.

**Available delivery events:**
- `onMessageAdded` — Message created
- `onMessageUpdated` — Message status changed
- `onDeliveryUpdated` — Delivery receipt received (SMS/WhatsApp only)

**Python (Flask)**
```python
@app.route("/conversations/webhook", methods=["POST"])
def delivery_webhook():
    event_type = request.form.get("EventType")
    
    if event_type == "onDeliveryUpdated":
        delivery_status = request.form.get("DeliveryStatus")
        message_sid = request.form.get("MessageSid")
        print(f"Message {message_sid}: {delivery_status}")
        # Status values: sent, delivered, failed, undelivered
    
    return "", 204
```

**Node.js (Express)**
```node
app.post("/conversations/webhook", (req, res) => {
    const { EventType, DeliveryStatus, MessageSid } = req.body;
    
    if (EventType === "onDeliveryUpdated") {
        console.log(`Message ${MessageSid}: ${DeliveryStatus}`);
        // Status values: sent, delivered, failed, undelivered
    }
    
    res.sendStatus(204);
});
```

### Conversation Attributes (Metadata)

Store custom metadata on conversations (order IDs, customer info, tags).

**Python**
```python
# Set attributes when creating
conversation = client.conversations.v1.conversations.create(
    friendly_name="Customer Support - Order #12345",
    attributes='{"order_id": "12345", "priority": "high", "customer_tier": "gold"}'
)

# Update attributes on existing conversation
client.conversations.v1 \
    .conversations(conversation.sid) \
    .update(attributes='{"order_id": "12345", "status": "resolved"}')

# Read attributes
conv = client.conversations.v1.conversations(conversation.sid).fetch()
import json
attrs = json.loads(conv.attributes)
print(f"Order ID: {attrs['order_id']}")
```

**Node.js**
```node
// Set attributes when creating
const conversation = await client.conversations.v1.conversations.create({
    friendlyName: "Customer Support - Order #12345",
    attributes: JSON.stringify({ orderId: "12345", priority: "high", customerTier: "gold" })
});

// Update attributes on existing conversation
await client.conversations.v1
    .conversations(conversationSid)
    .update({ attributes: JSON.stringify({ orderId: "12345", status: "resolved" }) });

// Read attributes
const conv = await client.conversations.v1.conversations(conversationSid).fetch();
const attrs = JSON.parse(conv.attributes);
console.log(`Order ID: ${attrs.orderId}`);
```

### Participant Attributes (Metadata)

Store metadata on individual participants (role, name, account info).

**Python**
```python
# Set attributes when adding participant
client.conversations.v1 \
    .conversations(conversation.sid) \
    .participants \
    .create(
        messaging_binding_address="+15558675310",
        messaging_binding_proxy_address="+15017122661",
        attributes='{"name": "John Doe", "role": "customer", "account_id": "A123"}'
    )

# Update participant attributes
client.conversations.v1 \
    .conversations(conversation.sid) \
    .participants(participant_sid) \
    .update(attributes='{"role": "vip_customer", "satisfaction": "high"}')
```

**Node.js**
```node
// Set attributes when adding participant
await client.conversations.v1
    .conversations(conversationSid)
    .participants.create({
        messagingBindingAddress: "+15558675310",
        messagingBindingProxyAddress: "+15017122661",
        attributes: JSON.stringify({ name: "John Doe", role: "customer", accountId: "A123" })
    });

// Update participant attributes
await client.conversations.v1
    .conversations(conversationSid)
    .participants(participantSid)
    .update({ attributes: JSON.stringify({ role: "vip_customer", satisfaction: "high" }) });
```

---

## Limits

| Limit | Value |
|-------|-------|
| Participants per conversation | 1,000 |
| Messages per conversation | Unlimited (older messages may be archived) |
| Message retention | Configurable (default: indefinite) |

---

## CANNOT

- **Cannot add SMS participants without a Twilio number** — Number must be assigned to a Conversations (classic) Service
- **Cannot send WhatsApp messages outside the 24-hour window** — Subject to service window rules. See `twilio-whatsapp-send-message`
- **Cannot use chat participants without Access Tokens** — Client-side SDK auth required. See `twilio-iam-auth-setup`
- **Cannot use WhatsApp Groups API** — Deprecated April 2020. Use Conversations (classic) API instead.
- **Conversations v1 (classic) is in maintenance mode** — Consider Conversations v2 API for new projects with enhanced features and scalability.

---

## Next Steps

- **WhatsApp setup and rules:** `twilio-whatsapp-send-message`
- **SMS setup:** `twilio-sms-send-message`
- **Access Tokens for chat clients:** `twilio-iam-auth-setup`
- **Webhook security:** `twilio-webhook-architecture`

From twilio/ai at 8aba46f, shown as plain text under its license: MIT (permissive). The license text is in LICENSE.

View SKILL.md on GitHub at 8aba46f

Files

4 files, 33 KB in total. Each file has a sha256 in the pin's manifest; the first 12 characters are shown.

Skill folder on GitHub at 8aba46f
All 50 skills from Twilio

More from Twilio

  • twilio-account-setup

    Sets up a Twilio account from scratch, including free trial signup, credential retrieval, phone number purchase, and enabling specific products like AI…

    Claude Code, Codex, Cursor +4 · about 2.5K tokens · pinned 6 days ago

  • twilio-agent-augmentation-architect

    This skill helps developers design AI-augmented contact center systems that enhance human agents with real-time intelligence.

    Claude Code, Codex, Cursor +3 · about 3.6K tokens · pinned 6 days ago

  • twilio-agent-connect

    Twilio Agent Connect is middleware that integrates LLM agents with Twilio communication channels (voice, SMS, RCS, WhatsApp, chat).

    Claude Code, Codex, Cursor +4 · about 4.1K tokens · pinned 6 days ago

  • twilio-ai-agent-architect

    Planning skill that helps developers design AI-powered conversational agents by assessing their use case across outcome sophistication, channels, and customer…

    Claude Code, Codex, Cursor +3 · about 4.9K tokens · pinned 6 days ago

  • twilio-call-recordings

    This skill teaches agents to record Twilio voice calls correctly using the appropriate method for the use case.

    Claude Code, Codex, Cursor +4 · about 2.6K tokens · pinned 6 days ago

  • twilio-cli-reference

    The Twilio CLI reference enables agents to manage Twilio resources directly from the terminal, including phone number provisioning, sending SMS and email…

    Claude Code, Codex, Cursor +4 · about 1.8K tokens · pinned 6 days ago

All Backend and APIs skills
  • twilio-conference-calls

    This skill enables multi-party call handling using Twilio Conference, covering warm and cold transfers, hold versus mute, supervisor coaching with whisper…

    by TwilioOfficial publisher

    Claude Code, Codex, Cursor +4 · about 2.8K tokens · pinned 6 days ago

  • twilio-content-template-builder

    This skill enables agents to create, manage, and send message templates through Twilio's Content API across WhatsApp, SMS, RCS, and MMS channels.

    by TwilioOfficial publisher

    Claude Code, Codex, Cursor +4 · about 1.3K tokens · pinned 6 days ago

  • twilio-conversation-orchestrator

    This skill configures Twilio Conversation Orchestrator to automatically capture and route SMS, voice, WhatsApp, RCS, and web chat into unified conversations.

    by TwilioOfficial publisher

    Claude Code, Codex, Cursor +4 · about 8.3K tokens · pinned 6 days ago

  • twilio-iam-auth-setup

    This skill guides agents through setting up Twilio authentication methods including Auth Tokens, API Keys (Standard, Main, Restricted), Access Tokens for…

    by TwilioOfficial publisher

    Claude Code, Codex, Cursor +4 · about 2.3K tokens · pinned 6 days ago

  • twilio-isv-sms-best-practices

    This skill guides ISVs building multi-tenant SMS platforms on Twilio through subaccount architecture, customer onboarding for A2P 10DLC and toll-free…

    by TwilioOfficial publisher

    Claude Code, Codex, Cursor +4 · about 2.7K tokens · pinned 6 days ago

  • twilio-lookup-phone-intelligence

    This skill validates phone numbers and retrieves intelligence data via Twilio Lookup v2 API, including line type detection, SIM swap status, caller name, and…

    by TwilioOfficial publisher

    Claude Code, Codex, Cursor +4 · about 1.2K tokens · pinned 6 days ago

The skills listed here are third-party software, collected from public GitHub repositories as a catalog of recent skills and provided as is. Agent Native does not write or control them and is not responsible for any harm, loss or damage caused by installing or using them. Labels and checks describe what we saw at one commit and are not a guarantee. Read a skill's files before you run it. Terms of use