> ## Documentation Index
> Fetch the complete documentation index at: https://docs.notifique.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Capabilities and blocking

> App ceiling, per-conversation switches, mute, and user blocks.

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

## App ceiling

The product declares what *may* exist:

| Field                                                    | Default                          | Meaning                                                   |
| -------------------------------------------------------- | -------------------------------- | --------------------------------------------------------- |
| `allowedMessageTypes`                                    | `text`, `image`, `audio`, `file` | Types a conversation can enable                           |
| `allowEdit`                                              | `false`                          | Ceiling for editing (v1 only stores the flag)             |
| `allowDeleteForEveryone`                                 | `false`                          | Ceiling for delete-for-everyone (v1 only stores the flag) |
| `allowUserManageCapabilities`                            | `false`                          | Whether a `USER` in DIRECT can change the room            |
| `defaultEnabledMessageTypes`                             | copies the ceiling               | What **starts on** in a new conversation                  |
| `defaultEditEnabled` / `defaultDeleteForEveryoneEnabled` | `false`                          | Initial flags for a new conversation                      |

`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:

```json theme={null}
{
  "capabilities": {
    "enabledMessageTypes": ["text"],
    "editEnabled": false,
    "deleteForEveryoneEnabled": false
  },
  "appCapabilities": {
    "allowedMessageTypes": ["text", "image", "audio", "file"],
    "allowEdit": false,
    "allowDeleteForEveryone": false,
    "allowUserManageCapabilities": false
  }
}
```

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 `USER`s → `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

* [Send messages](/en/chat-api/como-funciona/enviar-mensagens)
* [Webhook events](/en/chat-api/como-funciona/eventos-do-webhooks)
* [User and agent](/en/chat-api/como-funciona/usuario-e-agente)
