Backend

LAST EDIT Feb 16 2021

The majority of the integration is typically done client side. The React, React Native, Swift, Kotlin or Flutter SDKs connect to the chat API straight from the client. The backend integration is quite simple and usually consists of:

  • Generating user tokens and handing them to the client side

  • Syncing users

  • (optional) Syncing channels

  • (optional) Adding & Removing members & moderators

  • (optional) Sending messages

The backend has full access to the API. So if you have more complex use cases you can easily implement those. This quick start covers the basics of a backend integration. If we don't have an SDK for your favorite language be sure to review the REST documentation.

Client & User tokensCopied!

The backend creates a token for a user. You hand that token to the client side during login or registration. This token allows the client side to connect for that user. Stream's permission system determine if a users can send a message, add a reaction etc. So the backend just needs to provide a token to give the client side access to a specific user. The code below shows to how to instantiate a client and create a token for a user:

1
2
3
4
5
6
7
8
9
10
11
12
13
// yarn add stream-chat 
import { StreamChat } from 'stream-chat'; 
// if you're using common js 
const StreamChat = require('stream-chat').StreamChat; 
 
// instantiate your stream client using the API key and secret 
// the secret is only used server side and gives you full access to the API 
const client = StreamChat.getInstance('YOUR_API_KEY','YOUR_API_SECRET'); 
// you can still use new StreamChat('api_key', 'api_secret'); 
 
// generate a token for the user with id 'john' 
const token = client.createToken('john'); 
// next, hand this token to the client in your in your login or registration response
1
2
3
4
5
6
7
8
# pip install stream-chat 
from stream_chat import StreamChat 
 
# instantiate your stream client using the API key and secret 
# the secret is only used server side and gives you full access to the API 
client = StreamChat(api_key="YOUR_API_KEY", api_secret="YOUR_API_SECRET") 
token = chat_client.create_token('john') 
# next, hand this token to the client in your in your login or registration response
1
2
3
4
5
6
7
8
9
# gem install stream-chat-ruby 
 
require 'stream-chat' 
 
# instantiate your stream client using the API key and secret 
# the secret is only used server side and gives you full access to the API 
client = StreamChat::Client.new(api_key='YOUR_API_KEY', api_secret='YOUR_API_SECRET') 
client.create_token('john') 
# next, hand this token to the client in your in your login or registration response
1
2
3
4
5
6
7
// composer require get-stream/stream-chat 
 
// instantiate your stream client using the API key and secret 
// the secret is only used server side and gives you full access to the API 
$client = new GetStream\StreamChat\Client("YOUR_API_KEY", "YOUR_API_SECRET"); 
$token = $client->createToken("john"); 
// next, hand this token to the client in your in your login or registration response
1
2
3
4
5
6
7
// go get github.com/GetStream/stream-chat-go/v3 
 
// instantiate your stream client using the API key and secret 
// the secret is only used server side and gives you full access to the API 
client, _ := stream.NewClient("YOUR_API_KEY", "YOUR_API_SECRET") 
token := client.CreateToken("john", time.Time{}) 
// next, hand this token to the client in your in your login or registration response
1
2
3
4
5
6
7
8
9
// nuget install stream-chat-net 
 
using StreamChat; 
 
// instantiate your stream client using the API key and secret 
// the secret is only used server side and gives you full access to the API 
var client = new Client("YOUR_API_KEY", "YOUR_API_SECRET"); 
var token = client.CreateUserToken("john"); 
// next, hand this token to the client in your in your login or registration response
1
see [object Object]

You can also generate tokens that expire after a certain time. The tokens & authentication section explains this in detail.

Syncing UsersCopied!

When a user starts a chat conversation with another user both users need to be present in Stream's user storage. So you'll want to make sure that users are synced in advance. The update users endpoint allows you to update 100 users at once, an example is shown below:

1
2
3
4
5
const response = await client.upsertUsers([{  
    id: userID,  
    role: 'admin',  
    mycustomfield: '123' 
 }]);
1
client.update_users([{"id": user_id, "role": "admin", "mycustomfield": "123"}])
1
client.update_users([{ :id => userID, :role => 'admin', :mycustomfield => '123'}])
1
$client->updateUsers([['id' => 'bob-1', 'role' => 'admin', 'mycustomfield' => '123']]);
1
client.UpsertUser(&{ID: userID, Role: "admin", ExtraData: map[string]interface{}{"mycustomfield": "123"}})
1
2
3
4
5
6
7
8
var user = new User() 
{ 
    ID = "bob-1", 
    Role = Role.Admin 
}; 
user.SetData("mycustomfield", "123"); 
 
await client.Users.UpdateMany(new User[] { user });
1
2
3
4
5
6
7
8
curl --location --request POST 'https://chat-proxy-singapore.stream-io-api.com/users?api_key={api_key}' \ 
--header 'Accept: application/json' \ 
--header 'Stream-Auth-Type: jwt' \ 
--header 'Authorization: {{ YOUR TOKEN HERE }}' \ 
--header 'Content-Type: application/json' \ 
--data-raw '{ 
  "users":  { "Lakshmi": { "id" : "Lakshmi", "name": "Seethalakshmi" }}  
}'

Note that user roles can only be changed server side. The role you assign to a user impacts their permissions and which actions they can take on a channel.

Syncing ChannelsCopied!

You can create channels client side, but for many applications you'll want to restrict the creation of channels to the backend. Especially if a chat is related to a certain object in your database. One example is building a livestream chat like Twitch. You'll want to create a channel for each Stream and set the channel creator to the owner of the Stream. The example below shows how to create a channel and specify the moderators:

1
2
3
4
5
6
7
8
const channel = client.channel(type, id) 
// create the channel and set created_by to user id 4645 
const update = await channel.update({ 
    name: 'myspecialchannel', 
    image: 'imageurl', 
    mycustomfield: '123', 
    created_by_id: "4645" 
});
1
2
channel = chat.channel("messaging", "kung-fu") 
channel.update({"name": "my channel", "image": "image url", "mycustomfield": "123"})
1
2
3
4
5
$channel = $client->Channel("messaging", "bob-and-jane"); 
$update = $channel->update({ 
  'name'  => 'myspecialchannel',  
	'color' => 'green' 
});
1
2
chan = client.channel("messaging", channel_id: "bob-and-jane") 
   chan.update({ 'name' => 'my channel name', 'image' => 'my image url', 'mycustomfield' => '123' })
1
2
3
4
5
6
7
channel := client.Channel("messaging", "123") 
data := map[string]interface{}{ 
  "name": "my channel name", 
  "image": "img url", 
  "custom": "123", 
} 
channel.Update(data)
1
2
3
4
var chan = client.Channel("messaging", "bob-and-jane"); 
var newData = new GenericData(); 
newData.SetData("updated", "newValue"); 
await chan.Update(newData);
1

You can also add a message on the channel when updating it. It's quite common for chat apps to show messages like: "Jack invited John to the channel", or "Kate changed the color of the channel to green".

Adding Members or ModeratorsCopied!

The backend SDKs also make it easy to add or remove members from a channel. The example below shows how to add and remove members:

1
2
3
4
5
await channel.addMembers(['thierry', 'josh']); 
await channel.removeMembers(['tommaso']); 
 
await channel.addModerators(['thierry']); 
await channel.demoteModerators(['thierry']);
1
2
3
4
5
channel.add_members(['thierry', 'josh']) 
channel.remove_members(['tommaso']) 
 
channel.add_moderators(['thierry']); 
channel.demote_moderators(['thierry']);
1
2
3
4
5
$channel.addMembers(['thierry', 'josh']); 
$channel.removeMembers(['tommaso']); 
 
$channel.addModerators(['thierry']); 
$channel.demoteModerators(['thierry']);
1
2
3
4
5
channel.add_members(['thierry', 'josh']) 
channel.remove_members(['tommaso']) 
 
channel.add_moderators(['thierry']) 
channel.demote_moderators(['thierry'])
1
2
3
4
5
channel.AddMembers([]string{'thierry', 'josh'}); 
channel.RemoveMembers([]string{'tommaso'}); 
 
channel.AddModerators('thierry'); 
channel.DemoteModerators('thierry');
1
2
3
4
5
await channel.AddMembers(new string[] { 'thierry', 'josh' }); 
await channel.RemoveMembers(new string[] { 'tommaso' }); 
 
await channel.AddModerators(new string[] { 'thierry' }); 
await channel.DemoteModerators(new string[] { 'thierry' });
1
2
3
4
5
6
7
8
curl --location --request POST 'https://chat-proxy-singapore.stream-io-api.com/channels/{channel_type}/{cid}?api_key={api_key}' \ 
--header 'Accept: application/json' \ 
--header 'Stream-Auth-Type: jwt' \ 
--header 'Authorization: {{ YOUR TOKEN HERE }}' \ 
--header 'Content-Type: application/json' \ 
--data-raw '{ 
  "add_members" : ["Seetha", "Viswa"] 
}'

Sending MessagesCopied!

It's quite common that certain actions in your application trigger a message to be send. If a new user joins an app some chat apps will notify you that your contact joined the app. The example below shows how to send a message from the backend. It's the same syntax as you use client side, but specifying which user is sending the message is required:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const toBeSent = { 
    text: '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.', 
    attachments: [ 
        { 
            type: 'image', 
            asset_url: 'https://bit.ly/2K74TaG', 
            thumb_url: 'https://bit.ly/2Uumxti', 
            myCustomField: 123 
        } 
    ], 
    mentioned_users: [josh.id], 
    anotherCustomField: 234 
}; 
const message = await channel.sendMessage({ ...toBeSent, user_id: 'john' });
1
2
3
4
5
6
7
8
9
10
11
12
13
message = { 
    "text": '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.', 
    "attachments": [{ 
        "type": 'image', 
        "asset_url": 'https://bit.ly/2K74TaG', 
        "thumb_url": 'https://bit.ly/2Uumxti', 
        "myCustomField": 123 
    }], 
    "mentioned_users": [josh["id"]], 
   "anotherCustomField": 234, 
} 
 
channel.send_message(message, john["id"])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$toBeSent = [ 
    "text": "@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.", 
    "attachments": [ 
        [ 
            "type": "image", 
            "asset_url": "https://bit.ly/2K74TaG", 
            "thumb_url": "https://bit.ly/2Uumxti", 
            "myCustomField": 123 
        ] 
    ], 
    "mentioned_users": [josh.id], 
    "anotherCustomField": 234 
]; 
$channel->sendMessage($toBeSent, $john["id"]);
1
2
3
4
5
6
7
8
9
10
11
12
13
to_be_sent = { 
    'text' => '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.', 
    'attachments' => [{ 
        'type' => 'image', 
        'asset_url' => 'https://bit.ly/2K74TaG', 
        'thumb_url' => 'https://bit.ly/2Uumxti', 
        'myCustomField' => 123 
    }], 
    'mentioned_users' => [josh['id']], 
   'anotherCustomField' => 234 
}; 
 
channel.send_message(to_be_sent, john['id'])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var toBeSent = &Message{ 
    Text: '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.', 
    Attachments: []*Attachment{ 
        { 
            type: 'image', 
            asset_url: 'https://bit.ly/2K74TaG', 
            thumb_url: 'https://bit.ly/2Uumxti', 
            myCustomField: 123 
        } 
    }, 
    Mentioned_users: []*User{{ID: josh.ID}}, 
    ExtraData: map[string]interface{}{"anotherCustomField": 234}, 
} 
 
channel.SendMessage(toBeSent, john.ID)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var toBeSent = new MessageInput() 
{ 
    Text = '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.',     
    Mentioned_users = new string{ josh.ID } 
}; 
 
var attachment = new Attachment() 
{ 
    Type = "image", 
    AssetURL = 'https://bit.ly/2K74TaG', 
    ThumbURL = 'https://bit.ly/2Uumxti' 
}; 
attachment.SetData("myCustomField", 123); 
 
toBeSent.Attachments = new List<Attachment>() { attachment }; 
toBeSent.SetData("anotherCustomField", 234); 
 
channel.SendMessage(toBeSent, john.ID);
1
2
3
4
5
6
7
8
9
10
11
curl --location --request POST 'https://chat-proxy-singapore.stream-io-api.com/channels/{channel_type}/{cid}/message?api_key={api_key}' \ 
--header 'Stream-Auth-Type: jwt' \ 
--header 'Authorization: {{ YOUR TOKEN HERE }}' \ 
--header 'Content-Type: application/json' \ 
--data-raw '{ 
 "message" :  
 { 
     "text" : "Hello World", 
     "user" : { "id" : "Lakshmi" } 
   }  
}'

Note that if you want to send a marketing broadcast we also have a campaign API for that use case. The campaign API allows you to mass broadcast messages to a segment of your users. You can read the documentation here.