Conversations
A conversation is where members exchange messages inside one context. It has a type, a status and a list of members, and a few rules decide who may create it and who may change it.
| Type | Members | Visibility | Typical use |
|---|---|---|---|
DIRECT |
Exactly two, fixed | Private to its members | Coach and client |
GROUP |
Several | Private to its members | The “Morning squad” |
CHANNEL |
Few or many | PUBLIC (default) or PRIVATE |
announcements |
A channel with visibility: PUBLIC can be listed and read by any user of the application who holds conversations.read, without being a member. Writing still needs membership. A user joins a public channel themselves, and sending before that answers 403 not_conversation_member. DIRECT and GROUP conversations are always private, and visibility applies to channels only.
GROUP and CHANNEL need a name. A DIRECT conversation has none.
Status
Section titled “Status”| Status | Meaning |
|---|---|
ACTIVE |
Members can read and post. |
ARCHIVED |
Read-only. Members keep reading, and posting answers 422 conversation_archived. |
DELETED |
Soft-deleted. It no longer appears and answers 404. |
Archive when a relationship ends, for example when a coach stops coaching a client. Nothing is lost, and you can reactivate it later.
Membership roles
Section titled “Membership roles”A member has a role: OWNER, ADMIN or MEMBER. The user who creates a group or channel, or the actor_user_id your backend names, becomes its OWNER. Everyone else starts as MEMBER. A DIRECT conversation has no owner.
Renaming a group or channel and changing its status needs conversations.update, and the caller must be its OWNER or ADMIN or hold groups.manage or channels.manage. Adding and removing members follows the permissions:
| Conversation | Who may add or remove other members |
|---|---|
DIRECT |
Nobody. The two members never change. |
GROUP |
A holder of groups.manage, or an OWNER or ADMIN who also holds groups.create |
CHANNEL |
A holder of channels.manage. A user may also join a PUBLIC channel themselves. |
A member can always leave a group or channel. If your members must follow your business rules, leave groups.create ungranted so only your backend changes group membership.
Every member must be an active tenant member with access to the application. Otherwise Chat answers 422 target_user_not_eligible.
Who creates what
Section titled “Who creates what”Your backend --- machine token ---> create DIRECT [coach-ana, client-john] (after checking its own rules)Ana's app --- user token ------> read, send, react in it (no conversations.create needed)| Type | A user needs | A backend client needs |
|---|---|---|
DIRECT |
conversations.create |
chat:conversations.manage (or chat:sync) |
GROUP |
conversations.create and groups.create |
also chat:groups.manage |
CHANNEL |
conversations.create and channels.create |
also chat:channels.manage |
conversations.createUser scope: chat:accessMachine scope (any of): chat:conversations.managechat:syncA machine must send member_user_ids with every member. A user sends the other members, and is added automatically. For the backend-driven pattern, grant users no create permissions at all; see Chat permissions.
DIRECT conversations
Section titled “DIRECT conversations”- They dedupe. A
DIRECTconversation is identified by its two members within the context. Creating it again returns the existing one, so calling create every time is safe. - They are immutable. You cannot rename them or change their members. The one change allowed is the status, and only a backend client may make it. A user who tries gets 422
direct_conversation_immutable. - Archive and reopen. Your backend archives a
DIRECTconversation when the relationship ends. Users cannot reopen it.
What a list returns
Section titled “What a list returns”A user’s list holds the conversations they belong to, plus PUBLIC channels. A backend client’s list holds every conversation in its application. Each item carries member_count, and for users my_role and has_unread. DIRECT and GROUP items embed a bounded member list. Channels omit it, so list their members separately. Lists page with a cursor; see Pagination.