Skip to main content
There are two layers, Stream/Sendbird-style: the app declares the ceiling; each conversation turns on a subset. Block and mute belong to the person, not the room.

App ceiling

The product declares what may exist: PATCH /v1/chat/apps/{id} (scope chat:apps:manage) changes the ceiling. A conversation cannot enable video if the app has no video.

Conversation switch

Serialized on GET/list:
Creating a conversation applies the app default; the body may pass a subset. PATCH /v1/chat/conversations/{id} flips the switch and emits conversation.updated (WebSocket) and chat.conversation.updated (webhook). Who can change the conversation
  • API Key: always
  • AGENT: always
  • GROUP + OWNER (and ADMIN): yes
  • USER in DIRECT: only if allowUserManageCapabilities is on

Send rejected

The client composer only hides buttons. The server is the source of truth:
  • Type outside the room or the ceiling → CHAT_CAPABILITY_DISABLED (403)
  • DIRECT with a block between the USERs → CHAT_USER_BLOCKED (403)
Agents also respect the room. Same rules on REST and WebSocket (message.send with type + mediaUrl). recording.start requires audio on. Support example: the app allows text, image, audio, and file. A ticket conversation starts text only. The agent (or API Key) turns media on in that room. Turning it off again refuses IMAGE / AUDIO / FILE.

Mute

POST /v1/chat/conversations/{id}/mute
  • JWT: mutes self
  • API Key: send memberExternalUserId
mutedUntil null or muted: false turns it off. A muted member still sends and reads; the field is members[].mutedUntil. WebSocket event: member.updated.

Block

Per Chat App (PUT / DELETE / GET /v1/chat/blocks/{externalUserId}).
  • Does not create a DIRECT with the blocked user
  • Does not add them to a group (and they cannot join if joinPolicy=OPEN)
  • Existing DIRECT: send refused both ways
  • Does not delete history
  • USER blocks USER. You cannot block an AGENT
  • With an API Key, send chatAppId and blockerExternalUserId
Events: WebSocket user.blocked / user.unblocked on affected DIRECT conversations; webhooks chat.user.blocked / chat.user.unblocked. Removing a member is still “leave the room”, not a global block.

Next steps