Skip to content

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 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.

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.

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
Chat permission: conversations.createUser scope: chat:accessMachine scope (any of): chat:conversations.managechat:sync

A 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.

  • They dedupe. A DIRECT conversation 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 DIRECT conversation when the relationship ends. Users cannot reopen it.

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.