Customer{"channelSid":"CH********","name":"Customer","channelType":"web"}. Note that the channelSid is the SID of the chat channel created abovechannelType: Which type of channel this chat is using. There are some predefined one (web, facebook, sms, whatsapp, line) or you can use custom for your own channel. You can define multiple Flex Flows for a channelType, but only one can have the enabled property set to trueintegrationType: Which product the flow integrates with to handle incoming messages. The allowed values are: studio: A new message will trigger a Twilio Studio flow. This is particularly useful when you want to IVR / chatbot to your chat before transferring it to an Agent. task: A new message will trigger the creation of a Task in Twilio TaskRouterexternal: A new message will trigger a call to your own Webhook. You can use that to integrate the flow with your infrastructure or other Twilio products. At the end of your flow, if you want your chat to be handled by Flex you need to create a new Task in the Flex TaskRouter Workspaceintegration: this is an object that holds properties related to the specific inegrationType. See more on this later. chatServiceSid: The sid of the Chat Service that will be used when creating a new Channel for a new chat integration property can have the following values: integration.flowSid: the Twilio Studio Flow SID (FWXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX)integration.workspaceSid: The Twilio TaskRouter Workspace SID (WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX)integration.workflowSid: The Twilio TaskRouter Workflow SID (WWXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX). The Workflow must belong to the Workspace defined aboveintegration.creationOnMessage: If set to true the Task is created when the first message is received. By default, the Task is created when the channel is added. integration.url: The URL of your Webhook{"name": "{{trigger.message.ChannelAttributes.from}}", "channelType": "web", "channelSid": "{{trigger.message.ChannelSid}}"}$ twilio api:flex:v1:flex-flows:create \ --friendly-name="Custom Webchat Flex Flow" \ --channel-type=custom \ --integration.channel=studio \ --chat-service-sid=<Flex Chat Service SID> \ --integration.flow-sid=<Flex Studio Flow SID> \ --contact-identity=custom \ --enabled createNewChannel() and sendChatMessage(). client.flexApi.channel.create() in lines from 2 to 9 of the code below. onMessageSent event of the chat channel. This is implemented using the JavaScript client.chat.services().channels().webhooks.create() in lines from 12 to 20 below. function createNewChannel(flexFlowSid, flexChatService, chatUserName) { return client.flexApi.channel .create({ flexFlowSid: flexFlowSid, identity: chatUserName, chatUserFriendlyName: chatUserName, chatFriendlyName: 'Flex Custom Chat', target: chatUserName }) .then(channel => { console.log(`Created new channel ${channel.sid}`); return client.chat .services(flexChatService) .channels(channel.sid) .webhooks.create({ type: 'webhook', 'configuration.method': 'POST', 'configuration.url': `${webhookUrl}/new-message?channel=${channel.sid}`, 'configuration.filters': ['onMessageSent'] }); }) .then(webhook => webhook.channelSid) .catch(error => {console.log(error)}) } target property correctly. This represents the Target Contact Identity (e.g., the To phone number for an SMS). If a chat channel with the same target value is already present, then Flex will use the existing channel instead of creating a new one. That also means that the Studio flow is not triggered, and a new task is not created. target value is also used in the Flex UI as the name of the new task. This is what a new task looks like for a channel with a target value set to "custom-chat-user"X-Twilio-Webhook-Enabled is set to true in the HTTP request: const fetch = require('node-fetch'); var base64 = require('base-64'); ... function sendChatMessage(serviceSid, channelSid, body) { const params = new URLSearchParams(); params.append('Body', body); params.append('From', chatUserName); return fetch( `https://chat.twilio.com/v2/Services/${serviceSid}/Channels/${channelSid}/Messages`, { method: 'post', body: params, headers: { 'X-Twilio-Webhook-Enabled': 'true', Authorization: `Basic ${base64.encode(`${ process.env.TWILIO_ACCOUNT_SID}:${process.env.TWILIO_AUTH_TOKEN}`)}` } } ) } /new-message) that will handle the message coming from flex. This is the webhook URL we configured in the createNewChannel() function defined above:app.post('/new-message', function(request, response) { console.log('New message from Flex'); if (request.body.Source === 'SDK' ) { io.emit('chat message', request.body.Body); } response.sendStatus(200); }); flexChannel global variable. This works well for this specific demo, but you may want to implement different logic for that in a production instance. ... async function sendMessageToFlex(msg) { if (!flexChannel) { flexChannel = await createNewChannel(process.env.FLEX_FLOW_SID, process.env.FLEX_CHAT_SERVICE, targetName, chatUserName); } sendChatMessage(process.env.FLEX_CHAT_SERVICE, flexChannel, msg); } ... io.on('connection', function(socket) { console.log('User connected'); socket.on('chat message', function(msg) { sendMessageToFlex(msg); io.emit('chat message', msg); }); }); onChannelUpdated event. You can do so adding a new webhook creation in the createNewChannel() function: function createNewChannel(flexFlowSid, flexChatService, chatUserName) { return client.flexApi.channel .create({ ... }) .then(channel => { console.log(`Created new channel ${channel.sid}`); return client.chat .services(flexChatService) .channels(channel.sid) .webhooks.create(...) .then(() => client.chat .services(flexChatService) .channels(channel.sid) .webhooks.create({ type: 'webhook', 'configuration.method': 'POST', 'configuration.url': '`${process.env.WEBHOOK_BASE_URL}/channel-update', 'configuration.filters': ['onChannelUpdated'] })) }) .then(webhook => webhook.channelSid) .catch(error => { console.log(error); }); } Attributes value in the POST request. This is a JSON object that contains a status key. When the Agent ends the chat, the status is set to "INACTIVE". You should monitor this status change to ensure that you gracefully close the chat and perform any necessary clean-up operations in your middleware and backend.