Create conversations programmatically
Active creation lets you populate conversations through the Conversation Orchestrator API or TwiML.
For a comparison with passive ingestion and guidance on which mode to use, see Ingestion modes.
- Create a Twilio account.
- Buy a voice- and SMS-enabled phone number.
- Store your Twilio credentials in environment variables.
- Create a memory store.
Send a POST request to the Configurations endpoint. Omit captureRules and use GROUP_BY_PROFILE so that conversations follow the same customer across channels and devices:
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createConfiguration() {14const configuration = await client.conversations.v2.configurations.create({15displayName: "active-conversations",16description: "Configuration for API-created conversations",17conversationGroupingType: "GROUP_BY_PROFILE",18memoryStoreId: "YOUR_MEMORY_STORE_ID",19channelSettings: {20SMS: {21statusTimeouts: {22inactive: 30,23closed: 1440,24},25},26},27});2829console.log(configuration.statusUrl);30}3132createConfiguration();
Configuration creation is asynchronous. Poll the returned statusUrl until status is COMPLETED.
Send a POST request to the Conversations endpoint with the participants you want to include. Always set the participant type explicitly so that profile resolution runs against the correct address.
1// Download the helper library from https://www.twilio.com/docs/node/install2const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";34// Find your Account SID at twilio.com/console5// Provision API Keys at twilio.com/console/runtime/api-keys6// and set the environment variables. See http://twil.io/secure7// For local testing, you can use your Account SID and Auth token8const accountSid = process.env.TWILIO_ACCOUNT_SID;9const apiKey = process.env.TWILIO_API_KEY;10const apiSecret = process.env.TWILIO_API_SECRET;11const client = twilio(apiKey, apiSecret, { accountSid: accountSid });1213async function createConversationWithConfig() {14const conversation = await client.conversations.v2.conversations.create({15configurationId: "YOUR_CONFIGURATION_ID",16name: "Support chat for Kiran",17participants: [18{19name: "Kiran A.",20type: "CUSTOMER",21addresses: [22{23channel: "SMS",24address: "+15551234567",25},26],27},28{29name: "Kai B.",30type: "HUMAN_AGENT",31addresses: [32{33channel: "SMS",34address: "YOUR_TWILIO_PHONE_NUMBER",35},36],37},38],39});4041console.log(conversation.id);42}4344createConversationWithConfig();
To add a participant after a conversation is created, send a POST request to the Participants endpoint on the conversation.
For voice channels, you can use TwiML to ingest calls into conversations. Conversation Orchestrator adds the call (and its transcription) to the conversation you specify.
| TwiML verb | Architecture | Use case |
|---|---|---|
<ConversationRelay> | Synchronous bidirectional STT + TTS over WebSocket. | AI voice agents. |
<Transcription> | Asynchronous fork of voice media for transcription. | Human agent augmentation. |
Use <ConversationRelay> with conversationConfiguration to start a new conversation using the given configuration:
1<Response>2<Connect>3<ConversationRelay4url="wss://your-voice-adapter/ws"5conversationConfiguration="YOUR_CONFIGURATION_ID" />6</Connect>7</Response>
Use <Transcription> with conversationId to add the call to a conversation you already created:
1<Response>2<Start>3<Transcription conversationId="YOUR_CONVERSATION_ID" />4</Start>5<Say>Welcome to support. How can I help you today?</Say>6</Response>
Both <ConversationRelay> and <Transcription> accept conversationConfiguration and conversationId. If both are present, conversationId takes precedence and grouping rules are bypassed.
| Parameters provided | Behavior |
|---|---|
conversationConfiguration only | Uses the configuration's grouping rules to find or create a conversation. |
conversationId only | Routes directly to the specified conversation. Grouping rules are bypassed. |
Both conversationConfiguration and conversationId | conversationId takes precedence. The configuration is ignored for routing. |
| Neither | No Conversation Orchestrator integration. Transcription isn't captured. |
When handing off from an AI agent to a human agent on the same call, end the Conversation Relay session and start <Transcription> with the same conversationId:
1<Response>2<Start>3<Transcription conversationId="YOUR_CONVERSATION_ID" />4</Start>5<Dial>+15551234567</Dial>6</Response>
Both the AI portion and the human portion live in one conversation.
Don't combine capture rules with active TwiML for the same call
If your configuration has voice capture rules and you pass conversationConfiguration on a <ConversationRelay> verb for the same call, you pay for STT twice. Remove voice capture rules from your configuration when using active TwiML with Conversation Relay. See the Voice channel documentation.
- Ingestion modes: Compare active and passive modes and learn about when to combine them.
- Profiles: Learn how participant types and addresses resolve to profiles.
- Conversation lifecycle: Control when conversations close.
- Connect Conversations API (classic): Bring existing Conversations API (classic) services into Conversation Orchestrator.