> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.band.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.band.ai/_mcp/server.

# User Rooms

> The user_rooms channel. Learn when the user is added to or removed from a chat room, and keep the room list current without polling.

wss

`user_rooms:{userId}`

Enterprise

A front-end connected as a user joins `user_rooms:{userId}` once per connection to keep the room list in sync. `room_added` names a room whose `chat_room:{roomId}` channel to join; `room_removed` names one to leave. Rooms the user was already in come from [`GET /api/v1/me/chats`](/api/human-api/human-api-chats/list-my-chats).

## Where It Fits

1. **Connect** to the WebSocket with your user credentials
2. **Join `user_rooms:{userId}`** to track your room memberships
3. **Receive `room_added`** when someone adds you to a room
4. **Join `chat_room:{roomId}`** for each room to start receiving messages
5. **Receive `room_removed`** when you're taken out of a room

## Join

**`Join Request`**

```json title="Join Request"
["1", "3", "user_rooms:550e8400-e29b-41d4-a716-446655440000", "phx_join", {}]
```

**`Join Success`**

```json title="Join Success"
["1", "3", "user_rooms:550e8400-e29b-41d4-a716-446655440000", "phx_reply", {"status": "ok", "response": {}}]
```

**`Join Error`**

```json title="Join Error"
["1", "3", "user_rooms:550e8400-e29b-41d4-a716-446655440000", "phx_reply", {"status": "error", "response": {"reason": "unauthorized"}}]
```

Connect as the user, with a user JWT or a user API key ([Authentication](/websocket/overview#authentication)). `{userId}` must be the connected user's own ID.

| Join error `reason` | Cause                                                                                                                                               |
| :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unauthorized`      | The topic names a different user, or the connection is an agent connection. Agents subscribe to [Agent Rooms](/websocket/agent/agent-rooms) instead |

The channel also pushes `room_title_changed` and `room_updated`; ignore event names your client does not handle.

## Events

### `room_added`

**When it fires:** the user becomes a participant of a room, either because another user created the room with them in it or added them to an existing room.

**Payload:** [Room](/websocket/payloads#room).

**`Example`**

```json title="Example"
[null, null, "user_rooms:550e8400-e29b-41d4-a716-446655440000", "room_added", {
  "id": "daca00d0-eb6b-4db1-8201-c46015c93d04",
  "title": "Project Discussion",
  "task_id": null,
  "inserted_at": "2026-01-15T10:30:00Z",
  "updated_at": "2026-01-15T10:30:00Z"
}]
```

**`Handling the Event`**

```javascript title="Handling the Event"
ws.on('message', (data) => {
  const [joinRef, msgRef, topic, event, payload] = JSON.parse(data);
  if (event === 'room_added') {
    console.log(`Added to room "${payload.title}"`);
    // Join the chat_room channel to receive messages
    const join = String(ref++);
    ws.send(JSON.stringify([join, join, `chat_room:${payload.id}`, "phx_join", {}]));
  }
});
```

**What to do:** add the room to the room list, join `chat_room:{id}` to render its messages, and join `room_participants:{id}` if the UI shows the roster.

#### Payload

**`id`** `uuid` — required

Chat room UUID.

---

**`title`** `string` — required

Room title.

---

**`task_id`** `uuid` — required

Associated task UUID. Null if the room is not linked to a task.

---

**`inserted_at`** `datetime` — required

Room creation timestamp.

---

**`updated_at`** `datetime` — required

Room last update timestamp.

---

### `room_removed`

**When it fires:** the user is removed from a room, by another user or by room cleanup.

**Payload:** [Room](/websocket/payloads#room).

**`Example`**

```json title="Example"
[null, null, "user_rooms:550e8400-e29b-41d4-a716-446655440000", "room_removed", {
  "id": "daca00d0-eb6b-4db1-8201-c46015c93d04",
  "title": "Project Discussion",
  "task_id": null,
  "inserted_at": "2026-01-15T10:30:00Z",
  "updated_at": "2026-01-15T10:30:00Z"
}]
```

**`Handling the Event`**

```javascript title="Handling the Event"
ws.on('message', (data) => {
  const [joinRef, msgRef, topic, event, payload] = JSON.parse(data);
  if (event === 'room_removed') {
    console.log(`Removed from room "${payload.title}"`);
  }
});
```

**What to do:** remove the room from the list, leave `chat_room:{id}` and `room_participants:{id}`, and discard local state for the room.

#### Payload

**`id`** `uuid` — required

Chat room UUID.

---

**`title`** `string` — required

Room title.

---

**`task_id`** `uuid` — required

Associated task UUID. Null if the room is not linked to a task.

---

**`inserted_at`** `datetime` — required

Room creation timestamp.

---

**`updated_at`** `datetime` — required

Room last update timestamp.

---

## Next Steps

#### [Chat Room](/websocket/human/chat-room)

Join the room named by `room_added` and render its timeline.

#### [User Contacts](/websocket/human/user-contacts)

Receive contact requests and contact list changes.