← Twilio Developer KitCONTENT HISTORY

Update to Twilio Developer Kit

Snapshot Sep 30, 2026 · 22:50 UTC · version 0.2.2

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "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.",
  "included_files": [
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 245
    }
  ],
  "skill_md_contents": "---\nname: twilio-conversations-classic-api\ndescription: >\n  Build multi-channel messaging experiences using Twilio Conversations (classic) API.\n  Covers creating conversations, adding participants (SMS, WhatsApp, chat),\n  sending messages, and handling webhooks. Use this skill to manage persistent\n  multi-party or multi-channel conversations beyond single-message SMS/WhatsApp.\n---\n\n## Overview\n\nConversations (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.\n\n**Note:** This is the Conversations (classic) API (v1).\n\n---\n\n## Prerequisites\n\n- Twilio account with Conversations (classic) enabled\n  — New to Twilio? See `twilio-account-setup`\n  — Enable at: [Console > Conversations > Manage > Overview](https://console.twilio.com/us1/develop/conversations/manage/overview) > **Enable Conversations**\n- Environment variables:\n  - `TWILIO_ACCOUNT_SID`\n  - `TWILIO_AUTH_TOKEN`\n  — See `twilio-iam-auth-setup` for credential setup and best practices\n- SDK: `pip install twilio` / `npm install twilio`\n- For SMS/WhatsApp participants: a Twilio number assigned to a Conversations Service\n\n---\n\n## Setup: Create a Conversation Service (classic)\n\nA 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.\n\n**Python**\n```python\nimport os\nfrom twilio.rest import Client\n\nclient = Client(os.environ[\"TWILIO_ACCOUNT_SID\"], os.environ[\"TWILIO_AUTH_TOKEN\"])\n\n# Create a Conversation Service\nservice = client.conversations.v1.services.create(\n    friendly_name=\"Customer Support Service\"\n)\nprint(f\"Service SID: {service.sid}\")\n```\n\n**Node.js**\n```node\nconst twilio = require(\"twilio\");\nconst client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);\n\n// Create a Conversation Service\nconst service = await client.conversations.v1.services.create({\n    friendlyName: \"Customer Support Service\"\n});\nconsole.log(`Service SID: ${service.sid}`);\n```\n\n**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.\n\n---\n\n## Quickstart\n\n**Python**\n```python\nimport os\nfrom twilio.rest import Client\n\nclient = Client(os.environ[\"TWILIO_ACCOUNT_SID\"], os.environ[\"TWILIO_AUTH_TOKEN\"])\n\n# Create a conversation (use default service or specify service_sid)\nconversation = client.conversations.v1.conversations.create(\n    friendly_name=\"Customer Support - Order #12345\"\n)\n\n# Add an SMS participant\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .participants \\\n    .create(\n        messaging_binding_address=\"+15558675310\",\n        messaging_binding_proxy_address=\"+15017122661\"\n    )\n\n# Send a message\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .messages \\\n    .create(body=\"Hello! How can I help you today?\", author=\"support-agent\")\n```\n\n**Node.js**\n```node\nconst twilio = require(\"twilio\");\nconst client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);\n\n// Create a conversation (use default service or specify serviceSid)\nconst conversation = await client.conversations.v1.conversations.create({\n    friendlyName: \"Customer Support - Order #12345\",\n});\n\n// Add an SMS participant\nawait client.conversations.v1\n    .conversations(conversation.sid)\n    .participants.create({\n        messagingBindingAddress: \"+15558675310\",\n        messagingBindingProxyAddress: \"+15017122661\",\n    });\n\n// Send a message\nawait client.conversations.v1\n    .conversations(conversation.sid)\n    .messages.create({ body: \"Hello! How can I help you today?\", author: \"support-agent\" });\n```\n\n---\n\n## Key Patterns\n\n### Add Participants by Channel\n\n**WhatsApp participant — Python**\n```python\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .participants \\\n    .create(\n        messaging_binding_address=\"whatsapp:+15558675310\",\n        messaging_binding_proxy_address=\"whatsapp:+14155238886\"\n    )\n```\n\n**WhatsApp participant — Node.js**\n```node\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .participants.create({\n        messagingBindingAddress: \"whatsapp:+15558675310\",\n        messagingBindingProxyAddress: \"whatsapp:+14155238886\",\n    });\n```\n\n**Chat participant (web/mobile) — Python**\n```python\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .participants \\\n    .create(identity=\"user-123\")\n```\n\n**Chat participant (web/mobile) — Node.js**\n```node\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .participants.create({ identity: \"user-123\" });\n```\n\n### Send Media (All Channels)\n\n**Python**\n```python\n# Send a message with media\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .messages \\\n    .create(\n        body=\"Check out this image!\",\n        author=\"support-agent\",\n        media_url=\"https://example.com/image.jpg\"\n    )\n\n# Multiple media URLs (up to 10)\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .messages \\\n    .create(\n        body=\"Here are the documents\",\n        author=\"support-agent\",\n        media_url=[\n            \"https://example.com/doc1.pdf\",\n            \"https://example.com/doc2.pdf\"\n        ]\n    )\n```\n\n**Node.js**\n```node\n// Send a message with media\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .messages.create({\n        body: \"Check out this image!\",\n        author: \"support-agent\",\n        mediaUrl: \"https://example.com/image.jpg\"\n    });\n\n// Multiple media URLs (up to 10)\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .messages.create({\n        body: \"Here are the documents\",\n        author: \"support-agent\",\n        mediaUrl: [\n            \"https://example.com/doc1.pdf\",\n            \"https://example.com/doc2.pdf\"\n        ]\n    });\n```\n\nMedia 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.\n\n### Add Multiple Participants\n\n**Python**\n```python\n# Add multiple SMS participants to a conversation\nparticipant_numbers = [\n    \"+15558675310\",\n    \"+15558675311\",\n    \"+15558675312\"\n]\n\ntwilio_number = \"+15017122661\"\n\nfor phone_number in participant_numbers:\n    client.conversations.v1 \\\n        .conversations(conversation.sid) \\\n        .participants \\\n        .create(\n            messaging_binding_address=phone_number,\n            messaging_binding_proxy_address=twilio_number\n        )\n```\n\n**Node.js**\n```node\n// Add multiple SMS participants to a conversation\nconst participantNumbers = [\n    \"+15558675310\",\n    \"+15558675311\",\n    \"+15558675312\"\n];\n\nconst twilioNumber = \"+15017122661\";\n\nfor (const phoneNumber of participantNumbers) {\n    await client.conversations.v1\n        .conversations(conversationSid)\n        .participants.create({\n            messagingBindingAddress: phoneNumber,\n            messagingBindingProxyAddress: twilioNumber\n        });\n}\n```\n\n### Fetch Message History\n\n**Python**\n```python\n# Get all messages from a conversation\nmessages = client.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .messages \\\n    .list(limit=50)\n\nfor message in messages:\n    print(f\"{message.author}: {message.body}\")\n```\n\n**Node.js**\n```node\n// Get all messages from a conversation\nconst messages = await client.conversations.v1\n    .conversations(conversationSid)\n    .messages\n    .list({ limit: 50 });\n\nmessages.forEach(message => {\n    console.log(`${message.author}: ${message.body}`);\n});\n```\n\n### List Conversations\n\n**Python**\n```python\n# List all conversations\nconversations = client.conversations.v1.conversations.list(limit=20)\n\nfor conv in conversations:\n    print(f\"{conv.friendly_name} - {conv.sid}\")\n\n# Filter by state\nactive_conversations = client.conversations.v1.conversations.list(\n    state=\"active\",\n    limit=20\n)\n```\n\n**Node.js**\n```node\n// List all conversations\nconst conversations = await client.conversations.v1.conversations.list({ limit: 20 });\n\nconversations.forEach(conv => {\n    console.log(`${conv.friendlyName} - ${conv.sid}`);\n});\n\n// Filter by state\nconst activeConversations = await client.conversations.v1.conversations.list({\n    state: \"active\",\n    limit: 20\n});\n```\n\n### Remove Participants\n\n**Python**\n```python\n# Remove a participant by participant SID\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .participants(participant_sid) \\\n    .delete()\n\n# Find and remove by phone number\nparticipants = client.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .participants \\\n    .list()\n\nfor p in participants:\n    if p.messaging_binding and p.messaging_binding.get(\"address\") == \"+15558675310\":\n        client.conversations.v1 \\\n            .conversations(conversation.sid) \\\n            .participants(p.sid) \\\n            .delete()\n```\n\n**Node.js**\n```node\n// Remove a participant by participant SID\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .participants(participantSid)\n    .remove();\n\n// Find and remove by phone number\nconst participants = await client.conversations.v1\n    .conversations(conversationSid)\n    .participants\n    .list();\n\nfor (const p of participants) {\n    if (p.messagingBinding?.address === \"+15558675310\") {\n        await client.conversations.v1\n            .conversations(conversationSid)\n            .participants(p.sid)\n            .remove();\n    }\n}\n```\n\n### Close/Complete Conversations\n\n**Python**\n```python\n# Close a conversation (marks it inactive)\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .update(state=\"closed\")\n\n# Delete a conversation completely\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .delete()\n```\n\n**Node.js**\n```node\n// Close a conversation (marks it inactive)\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .update({ state: \"closed\" });\n\n// Delete a conversation completely\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .remove();\n```\n\n### Handle Incoming Messages (Webhook)\n\nConfigure at Console > Conversations > Manage > Global Webhooks.\n\n> **Security:** Always validate the `X-Twilio-Signature` header in production to confirm requests originate from Twilio. See `twilio-webhook-architecture` for validation patterns.\n\n**Python (Flask)**\n```python\nfrom twilio.request_validator import RequestValidator\n\n@app.route(\"/conversations/webhook\", methods=[\"POST\"])\ndef conversations_webhook():\n    validator = RequestValidator(os.environ[\"TWILIO_AUTH_TOKEN\"])\n    if not validator.validate(request.url, request.form, request.headers.get(\"X-Twilio-Signature\", \"\")):\n        return \"\", 403\n\n    event_type = request.form.get(\"EventType\")\n    conversation_sid = request.form.get(\"ConversationSid\")\n    author = request.form.get(\"Author\")\n\n    if event_type == \"onMessageAdded\" and author != \"support-agent\":\n        client.conversations.v1.conversations(conversation_sid).messages.create(\n            body=\"Thanks — an agent will be with you shortly.\",\n            author=\"support-bot\"\n        )\n    return \"\", 204\n```\n\n**Node.js (Express)**\n```node\napp.post(\"/conversations/webhook\", async (req, res) => {\n    const valid = twilio.validateRequest(\n        process.env.TWILIO_AUTH_TOKEN,\n        req.headers[\"x-twilio-signature\"],\n        `https://${req.headers.host}${req.originalUrl}`,\n        req.body\n    );\n    if (!valid) return res.status(403).send(\"Forbidden\");\n\n    const { EventType, ConversationSid, Author } = req.body;\n    if (EventType === \"onMessageAdded\" && Author !== \"support-agent\") {\n        await client.conversations.v1\n            .conversations(ConversationSid)\n            .messages.create({ body: \"Thanks — an agent will be with you shortly.\", author: \"support-bot\" });\n    }\n    res.sendStatus(204);\n});\n```\n\n---\n\n## Advanced Context\n\n### Message Delivery Status\n\nTrack message delivery through webhooks. Configure at Console > Conversations > Manage > Global Webhooks.\n\n**Available delivery events:**\n- `onMessageAdded` — Message created\n- `onMessageUpdated` — Message status changed\n- `onDeliveryUpdated` — Delivery receipt received (SMS/WhatsApp only)\n\n**Python (Flask)**\n```python\n@app.route(\"/conversations/webhook\", methods=[\"POST\"])\ndef delivery_webhook():\n    event_type = request.form.get(\"EventType\")\n    \n    if event_type == \"onDeliveryUpdated\":\n        delivery_status = request.form.get(\"DeliveryStatus\")\n        message_sid = request.form.get(\"MessageSid\")\n        print(f\"Message {message_sid}: {delivery_status}\")\n        # Status values: sent, delivered, failed, undelivered\n    \n    return \"\", 204\n```\n\n**Node.js (Express)**\n```node\napp.post(\"/conversations/webhook\", (req, res) => {\n    const { EventType, DeliveryStatus, MessageSid } = req.body;\n    \n    if (EventType === \"onDeliveryUpdated\") {\n        console.log(`Message ${MessageSid}: ${DeliveryStatus}`);\n        // Status values: sent, delivered, failed, undelivered\n    }\n    \n    res.sendStatus(204);\n});\n```\n\n### Conversation Attributes (Metadata)\n\nStore custom metadata on conversations (order IDs, customer info, tags).\n\n**Python**\n```python\n# Set attributes when creating\nconversation = client.conversations.v1.conversations.create(\n    friendly_name=\"Customer Support - Order #12345\",\n    attributes='{\"order_id\": \"12345\", \"priority\": \"high\", \"customer_tier\": \"gold\"}'\n)\n\n# Update attributes on existing conversation\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .update(attributes='{\"order_id\": \"12345\", \"status\": \"resolved\"}')\n\n# Read attributes\nconv = client.conversations.v1.conversations(conversation.sid).fetch()\nimport json\nattrs = json.loads(conv.attributes)\nprint(f\"Order ID: {attrs['order_id']}\")\n```\n\n**Node.js**\n```node\n// Set attributes when creating\nconst conversation = await client.conversations.v1.conversations.create({\n    friendlyName: \"Customer Support - Order #12345\",\n    attributes: JSON.stringify({ orderId: \"12345\", priority: \"high\", customerTier: \"gold\" })\n});\n\n// Update attributes on existing conversation\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .update({ attributes: JSON.stringify({ orderId: \"12345\", status: \"resolved\" }) });\n\n// Read attributes\nconst conv = await client.conversations.v1.conversations(conversationSid).fetch();\nconst attrs = JSON.parse(conv.attributes);\nconsole.log(`Order ID: ${attrs.orderId}`);\n```\n\n### Participant Attributes (Metadata)\n\nStore metadata on individual participants (role, name, account info).\n\n**Python**\n```python\n# Set attributes when adding participant\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .participants \\\n    .create(\n        messaging_binding_address=\"+15558675310\",\n        messaging_binding_proxy_address=\"+15017122661\",\n        attributes='{\"name\": \"John Doe\", \"role\": \"customer\", \"account_id\": \"A123\"}'\n    )\n\n# Update participant attributes\nclient.conversations.v1 \\\n    .conversations(conversation.sid) \\\n    .participants(participant_sid) \\\n    .update(attributes='{\"role\": \"vip_customer\", \"satisfaction\": \"high\"}')\n```\n\n**Node.js**\n```node\n// Set attributes when adding participant\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .participants.create({\n        messagingBindingAddress: \"+15558675310\",\n        messagingBindingProxyAddress: \"+15017122661\",\n        attributes: JSON.stringify({ name: \"John Doe\", role: \"customer\", accountId: \"A123\" })\n    });\n\n// Update participant attributes\nawait client.conversations.v1\n    .conversations(conversationSid)\n    .participants(participantSid)\n    .update({ attributes: JSON.stringify({ role: \"vip_customer\", satisfaction: \"high\" }) });\n```\n\n---\n\n## Limits\n\n| Limit | Value |\n|-------|-------|\n| Participants per conversation | 1,000 |\n| Messages per conversation | Unlimited (older messages may be archived) |\n| Message retention | Configurable (default: indefinite) |\n\n---\n\n## CANNOT\n\n- **Cannot add SMS participants without a Twilio number** — Number must be assigned to a Conversations (classic) Service\n- **Cannot send WhatsApp messages outside the 24-hour window** — Subject to service window rules. See `twilio-whatsapp-send-message`\n- **Cannot use chat participants without Access Tokens** — Client-side SDK auth required. See `twilio-iam-auth-setup`\n- **Cannot use WhatsApp Groups API** — Deprecated April 2020. Use Conversations (classic) API instead.\n- **Conversations v1 (classic) is in maintenance mode** — Consider Conversations v2 API for new projects with enhanced features and scalability.\n\n---\n\n## Next Steps\n\n- **WhatsApp setup and rules:** `twilio-whatsapp-send-message`\n- **SMS setup:** `twilio-sms-send-message`\n- **Access Tokens for chat clients:** `twilio-iam-auth-setup`\n- **Webhook security:** `twilio-webhook-architecture`\n"
}

SHA-256: 588d18117f5e1cbda4bdb2af68ac7cb9d3459197fe787b1c65c596e76e3d095f