Skip to content

Groups and channels

Create a GROUP such as “Morning squad” or a Channel such as announcements, and keep their members in line with your own data. Your backend decides who belongs; Chat enforces who may read and write.

Chat permissions (all of): conversations.creategroups.create
  • Groups need chat:conversations.manage and chat:groups.manage, which carry the permissions above. Channels need chat:conversations.manage and chat:channels.manage (conversations.create and channels.create). chat:sync covers both. See Grant Chat scopes.
  • The ChatClient from Create direct conversations.
  1. Create the group or channel. A GROUP or CHANNEL needs a name. Every member must be an eligible tenant member, or Chat answers 422 target_user_not_eligible. actor_user_id is recorded as the creator and as the OWNER.

  2. Add and remove members. addMember takes a user id and optional profile hints (display_name, email), used only if Chat has no profile for that user yet. Removing a member works the same way.

  3. Change it. update changes name, description and, for a channel, visibility (PUBLIC or PRIVATE). The default visibility is PUBLIC.

groups-and-channels.ts
import { chat } from './guide-chat-client';
export async function createMorningSquad(coachId: string): Promise<string> {
const group = await chat.conversations.create({
type: 'GROUP',
name: 'Morning squad',
member_user_ids: [coachId, 'client-john'], // every id must be an eligible tenant member
actor_user_id: coachId, // recorded as the creator and OWNER
});
// Profile hints are used only when Chat has no profile for the user yet.
await chat.conversations.addMember(group.conversation_id, { user_id: 'client-sarah', display_name: 'Sarah Client' });
await chat.conversations.removeMember(group.conversation_id, 'client-john');
return group.conversation_id;
}
export async function createAnnouncements(coachId: string): Promise<string> {
const channel = await chat.channels.create({
name: 'announcements',
visibility: 'PUBLIC',
member_user_ids: [coachId],
actor_user_id: coachId,
});
await chat.conversations.update(channel.conversation_id, { description: 'News from the coaches' });
const channels = await chat.channels.list({ limit: 20 });
return channels.items.map((c) => c.name ?? '').join(', ');
}
Conversation Who may add or remove members
DIRECT Nobody. Its members never change (direct_conversation_immutable).
GROUP Your backend with groups.manage, or a user who is its OWNER or ADMIN and holds groups.create.
CHANNEL Your backend with channels.manage. A user may also join a PUBLIC channel themselves.

A user can always leave a group or channel. Membership roles (OWNER, ADMIN, MEMBER) are about content ownership, never about authorization on their own.

A PUBLIC channel is readable by every tenant user who holds conversations.read. Sending requires being a member.

List the channels of your application and check the new one:

const { items } = await chat.channels.list({ limit: 20 }); // items[].name includes "announcements"

Page through members with chat.conversations.listMembers(id); each page returns next_cursor to pass as before.

Symptom Cause and fix
403 missing_capability on create The client lacks chat:groups.manage or chat:channels.manage.
400 invalid_request name is missing, or member_user_ids is empty.
422 direct_conversation_immutable You tried to add or remove members of a DIRECT conversation.
422 target_user_not_eligible A user is not an active member with access to your application.