# Integrate a Custom Chat Client with Flex

> \[!NOTE]
>
> This guide is for Flex UI 1.x.x and channels that use Programmable Chat and Proxy. Programmable Chat for Flex will reach end of life on June 1, 2026. If you're new to Flex or currently using Programmable Chat, [build with Flex Conversations](/docs/flex/conversations) or [migrate](/docs/flex/developer/conversations/programmable-chat-to-flex-conversations).

You may have already built a custom chat experience with [Programmable Chat](/docs/chat) or from scratch. You can integrate these chat experiences with Flex and hand off incoming Chat messages to your agents.

> \[!NOTE]
>
> Custom chat integrations require a Flex Flow `ChannelType` of `custom`.

## How to Integrate Your Chat Application with Flex

First, initialize the [Twilio Chat SDK](/docs/chat/sdk-download-install) using an access token that links a user with a unique identity - for example: `abc123`. The Chat SDK is going to help you pass messages back and forth with Flex.

> \[!WARNING]
>
> Make sure this identity uniquely identifies your end user and avoid using personally identifiable information like names.

Creating an Access Token (Chat)

```js
const AccessToken = require('twilio').jwt.AccessToken;
const ChatGrant = AccessToken.ChatGrant;

// Used when generating any kind of tokens
// To set up environmental variables, see http://twil.io/secure
const twilioAccountSid = process.env.TWILIO_ACCOUNT_SID;
const twilioApiKey = process.env.TWILIO_API_KEY;
const twilioApiSecret = process.env.TWILIO_API_SECRET;

// Used specifically for creating Chat tokens
const serviceSid = process.env.TWILIO_CHAT_SERVICE_SID;
const identity = 'user@example.com';

// Create a "grant" which enables a client to use Chat as a given user,
// on a given device
const chatGrant = new ChatGrant({
  serviceSid: serviceSid,
});

// Create an access token which we will sign and return to the client,
// containing the grant we just created
const token = new AccessToken(
  twilioAccountSid,
  twilioApiKey,
  twilioApiSecret,
  {identity: identity}
);

token.addGrant(chatGrant);

// Serialize the token to a JWT string
console.log(token.toJwt());
```

```py
import os
from twilio.jwt.access_token import AccessToken
from twilio.jwt.access_token.grants import ChatGrant

# required for all twilio access tokens
# To set up environmental variables, see http://twil.io/secure
account_sid = os.environ['TWILIO_ACCOUNT_SID']
api_key = os.environ['TWILIO_API_KEY']
api_secret = os.environ['TWILIO_API_KEY_SECRET']

# required for Chat grants
service_sid = 'ISxxxxxxxxxxxx'
identity = 'user@example.com'

# Create access token with credentials
token = AccessToken(account_sid, api_key, api_secret, identity=identity)

# Create an Chat grant and add to token
chat_grant = ChatGrant(service_sid=service_sid)
token.add_grant(chat_grant)

# Return token info as JSON
print(token.to_jwt())
```

```cs
using System;
using System.Collections.Generic;
using Twilio.Jwt.AccessToken;

class Example
{
    static void Main(string[] args)
    {
        // These values are necessary for any access token
        // To set up environmental variables, see http://twil.io/secure
        const string twilioAccountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        const string twilioApiKey = Environment.GetEnvironmentVariable("TWILIO_API_KEY");
        const string twilioApiSecret = Environment.GetEnvironmentVariable("TWILIO_API_SECRET");

        // These are specific to Chat
        const string serviceSid = Environment.GetEnvironmentVariable("TWILIO_SERVICE_SID");
        const string identity = "user@example.com";

        // Create an Chat grant for this token

        var grant = new ChatGrant
        {
          ServiceSid = serviceSid
        };

        var grants = new HashSet<IGrant>
        {
            { grant }
        };

        // Create an Access Token generator
        var token = new Token(
            twilioAccountSid,
            twilioApiKey,
            twilioApiSecret,
            identity,
            grants: grants);

        Console.WriteLine(token.ToJwt());
    }
}
```

```java
import com.twilio.jwt.accesstoken.AccessToken;
import com.twilio.jwt.accesstoken.ChatGrant;

public class Example {
  public static void main(String[] args) {
    // Get your Account SID from https://twilio.com/console
    // To set up environment variables, see http://twil.io/secure
    // Required for all types of tokens
    String twilioAccountSid = System.getenv("TWILIO_ACCOUNT_SID");
    String twilioApiKey = System.getenv("TWILIO_API_KEY");
    String twilioApiSecret = System.getenv("TWILIO_API_SECRET");

    String serviceSid = System.getenv("TWILIO_SERVICE_SID");
    String identity = "user@example.com";

    ChatGrant grant = new ChatGrant();
    grant.setServiceSid(serviceSid);

    AccessToken token = new AccessToken.Builder(twilioAccountSid, twilioApiKey, twilioApiSecret)
        .identity(identity).grant(grant).build();

    System.out.println(token.toJwt());
  }
}
```

```go
package main

import (
	"fmt"
	"os"

	"github.com/twilio/twilio-go/client/jwt"
)

func main() {
	// Get your Account SID from https://twilio.com/console
	// To set up environment variables, see http://twil.io/secure
	// Required for all types of tokens
	var twilioAccountSid string = os.Getenv("TWILIO_ACCOUNT_SID")
	var twilioApiKey string = os.Getenv("TWILIO_API_KEY")
	var twilioApiSecret string = os.Getenv("TWILIO_API_SECRET")

	params := jwt.AccessTokenParams{
		AccountSid:    twilioAccountSid,
		SigningKeySid: twilioApiKey,
		Secret:        twilioApiSecret,
		Identity:      "user@example.com",
	}

	jwtToken := jwt.CreateAccessToken(params)
	chatGrant := &jwt.ChatGrant{
		ServiceSid: "ISxxxxxxxxxxxx",
	}

	jwtToken.AddGrant(chatGrant)
	token, err := jwtToken.ToJwt()

	if err != nil {
		error := fmt.Errorf("error: %q", err)
		fmt.Println(error.Error())
	}

	fmt.Println(token)
}
```

```php
<?php
// Get the PHP helper library from https://twilio.com/docs/libraries/php
require_once '/path/to/vendor/autoload.php'; // Loads the library
use Twilio\Jwt\AccessToken;
use Twilio\Jwt\Grants\ChatGrant;

// Required for all Twilio access tokens
// To set up environmental variables, see http://twil.io/secure
$twilioAccountSid = getenv('TWILIO_ACCOUNT_SID');
$twilioApiKey = getenv('TWILIO_API_KEY');
$twilioApiSecret = getenv('TWILIO_API_KEY_SECRET');

// Required for Chat grant
$serviceSid = 'ISxxxxxxxxxxxx';
// choose a random username for the connecting user
$identity = "john_doe";

// Create access token, which we will serialize and send to the client
$token = new AccessToken(
    $twilioAccountSid,
    $twilioApiKey,
    $twilioApiSecret,
    3600,
    $identity
);

// Create Chat grant
$chatGrant = new ChatGrant();
$chatGrant->setServiceSid($serviceSid);

// Add grant to token
$token->addGrant($chatGrant);

// render token to string
echo $token->toJWT();
```

```rb
require 'twilio-ruby'

# Required for any Twilio Access Token
# To set up environmental variables, see http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
api_key = ENV['TWILIO_API_KEY']
api_secret = ENV['TWILIO_API_KEY_SECRET']

# Required for Chat
service_sid = 'ISxxxxxxxxxxxx'
identity = 'user@example.com'

# Create Chat grant for our token
grant = Twilio::JWT::AccessToken::ChatGrant.new
grant.service_sid = service_sid

# Create an Access Token
token = Twilio::JWT::AccessToken.new(
  account_sid,
  api_key,
  api_secret,
  [grant],
  identity: identity
)

# Generate the token
puts token.to_jwt
```

Now you need to:

1. Ensure you have a relevant Message Handler. You can add [Studio](/docs/studio) to the communication flow, immediately create a task, or do something else entirely depending on how you've configured your [Flex Flow](/docs/flex/developer/messaging/flow).
2. Create a Flex Chat Channel (or reuse one if this is a return customer and you're using Long Lived channels)

   1. Creating a Channel will also automatically create a Chat User and place it in the Channel.

This configuration could require a minimum of four API requests, but with Flex you can do everything with a single request to [Flex Chat Channels API](/docs/flex/developer/messaging/chat-channel).

Create a Flex Chat Channel

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function createChannel() {
  const channel = await client.flexApi.v1.channel.create({
    chatFriendlyName: "Chat with abc123",
    chatUserFriendlyName: "Jane",
    flexFlowSid: "FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    identity: "abc123",
    target: "abc123",
  });

  console.log(channel.accountSid);
}

createChannel();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

channel = client.flex_api.v1.channel.create(
    identity="abc123",
    target="abc123",
    chat_friendly_name="Chat with abc123",
    chat_user_friendly_name="Jane",
    flex_flow_sid="FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
)

print(channel.account_sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.FlexApi.V1;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var channel = await ChannelResource.CreateAsync(
            identity: "abc123",
            target: "abc123",
            chatFriendlyName: "Chat with abc123",
            chatUserFriendlyName: "Jane",
            flexFlowSid: "FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

        Console.WriteLine(channel.AccountSid);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.flexapi.v1.Channel;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        Channel channel = Channel.creator("FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "abc123", "Jane", "Chat with abc123")
                              .setTarget("abc123")
                              .create();

        System.out.println(channel.getAccountSid());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	flex "github.com/twilio/twilio-go/rest/flex/v1"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &flex.CreateChannelParams{}
	params.SetIdentity("abc123")
	params.SetTarget("abc123")
	params.SetChatFriendlyName("Chat with abc123")
	params.SetChatUserFriendlyName("Jane")
	params.SetFlexFlowSid("FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")

	resp, err := client.FlexV1.CreateChannel(params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.AccountSid != nil {
			fmt.Println(*resp.AccountSid)
		} else {
			fmt.Println(resp.AccountSid)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$channel = $twilio->flexApi->v1->channel->create(
    "FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // FlexFlowSid
    "abc123", // Identity
    "Jane", // ChatUserFriendlyName
    "Chat with abc123", // ChatFriendlyName
    ["target" => "abc123"]
);

print $channel->accountSid;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

channel = @client
          .flex_api
          .v1
          .channel
          .create(
            identity: 'abc123',
            target: 'abc123',
            chat_friendly_name: 'Chat with abc123',
            chat_user_friendly_name: 'Jane',
            flex_flow_sid: 'FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
          )

puts channel.account_sid
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:flex:v1:channels:create \
   --identity abc123 \
   --target abc123 \
   --chat-friendly-name "Chat with abc123" \
   --chat-user-friendly-name Jane \
   --flex-flow-sid FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```

```bash
curl -X POST "https://flex-api.twilio.com/v1/Channels" \
--data-urlencode "Identity=abc123" \
--data-urlencode "Target=abc123" \
--data-urlencode "ChatFriendlyName=Chat with abc123" \
--data-urlencode "ChatUserFriendlyName=Jane" \
--data-urlencode "FlexFlowSid=FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "flex_flow_sid": "FOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "sid": "CHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "task_sid": "WTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "user_sid": "USaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "date_created": "2016-08-01T22:10:40Z",
  "date_updated": "2016-08-01T22:10:40Z",
  "url": "https://flex-api.twilio.com/v1/Channels/CHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
```

### Bringing it all together

Now you can use the [Twilio Chat SDK to manage communications](/docs/chat/channels) on the Chat Channel you created with Flex:

* When **a message comes in**, you'll receive a `messageAdded` event and can render it in your custom UI.
* When **you need to send a message**, the SDK includes a `sendMessage()` method that you can use to publish media over the Twilio Chat Channel.
