Chat User Roles

Per-participant chat rows — the caller’s own row carries pin, mute, and the read cursor; membership and roles are managed at chat level.

Service: messages.chat_user_roles

Every participant of a chat has a ChatUserRole row. The collection is exposed as a first-class endpoint (per-row ownership can’t be a writable inline), but deliberately narrow: the only thing a client writes here is their own row’s preferencespinned and muted_until. Reads flow inline in the chat payload (one screen = one request), so no view scope is needed. Membership (user_id, role, wrapped_content_key, chat_id) is assigned at chat creation and is read-only on this endpoint.

All methods use the JSON-RPC 2.0 protocol over WebSocket. See Enbox API for transport details, error codes, query operators, and encryption model.

Fields

Full field reference: ChatUserRole. On this endpoint, for scoped callers:

Field Writable? Notes
pinned Pin/unpin the chat in your own list
muted_until ISO 8601 timestamp or null
last_read_message_id Normally written by chat.markRead, not directly
chat_id Read-only — re-pointing your row at another chat would be a self-serve invite
user_id Read-only — the row is yours, period
role Read-only — no self-escalation
wrapped_content_key Read-only — key material, set at creation

updateOneById

Patch the caller’s own role row — pin or mute a chat. Scoped to user_id == caller (write scope); anything outside your own row returns NotFound.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "messages.chat_user_roles.updateOneById",
  "params": {
    "id": "220226115493429249",
    "document": { "pinned": true }
  },
  "id": 1
}

Response

The updated role row (as it appears inline in the chat payload, including the computed username).

Mute example

{
  "jsonrpc": "2.0",
  "method": "messages.chat_user_roles.updateOneById",
  "params": {
    "id": "220226115493429249",
    "document": { "muted_until": "2027-08-31T00:00:00Z" }
  },
  "id": 2
}

"muted_until": null unmutes.