Data types
These are the objects you read from the Chat API and receive in realtime events. Each section lists every field, then a complete example from the Fitness app. The OpenAPI document holds the same schemas in machine-readable form.
Reading the tables
Section titled “Reading the tables”- Field names are snake_case, as everywhere in the API.
- Nullable means the field is always present and its value can be
null. A field marked optional can be missing from the response. - Timestamps are ISO-8601 strings in UTC, such as
2026-10-14T09:30:00.000Z. - Ids you receive from Chat for conversations, messages and members are UUIDs. Ids from the Identity Server (
tenant_id,application_id,user_id) are opaque strings: never assume their format. The examples use readable placeholders such asfitnessandcoach-ana. - Enum values are UPPER_CASE, except presence statuses, which are
onlineandoffline.
Conversation
Section titled “Conversation”A conversation of type DIRECT, GROUP or CHANNEL. See Conversations. Returned by Conversations_list, Conversations_get, create and update, and sent as conversation in conversation.created and conversation.updated.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
conversation_id |
string | no | The conversation’s id. |
tenant_id |
string | no | The Identity Server tenant id. |
application_id |
string | no | The Identity Server application id: the context. |
type |
DIRECT, GROUP, CHANNEL |
no | The conversation type. |
visibility |
PUBLIC, PRIVATE |
yes | For a CHANNEL only; null for the other types. |
name |
string | yes | The name of a GROUP or CHANNEL; null for a DIRECT conversation. |
description |
string | yes | An optional description. |
status |
ACTIVE, ARCHIVED, DELETED |
no | ARCHIVED conversations are read-only. |
created_by_user_id |
string | yes | The user who created it. null when a backend client created it without acting on behalf of a user. |
created_by_client_id |
string | yes | Set when a backend client created it. |
last_activity_at |
string | no | When the last message arrived; the list is sorted by this. |
created_at |
string | no | When it was created. |
updated_at |
string | no | When it last changed. |
members |
array of UserRef | optional | The active members of a DIRECT or GROUP, up to a bounded number. Omitted for a CHANNEL. |
member_count |
number | optional | The number of active members. |
my_role |
OWNER, ADMIN, MEMBER |
yes, optional | The caller’s membership role. null for backend clients and for callers who are not members. |
has_unread |
boolean | optional | Whether the caller has unread messages. Always false for backend clients. |
my_role and has_unread describe the caller. In a realtime event they describe the user or client that caused the event, not the user who receives it.
{ "conversation_id": "3f7c2a9e-5b1d-4e8a-9c63-1a2b3c4d5e6f", "tenant_id": "fitness", "application_id": "fitness-app", "type": "GROUP", "visibility": null, "name": "Morning squad", "description": null, "status": "ACTIVE", "created_by_user_id": null, "created_by_client_id": "2f1c9e5a-7f4d-4f0e-8c35-9b1a3d6e4c21", "last_activity_at": "2026-10-14T09:30:00.000Z", "created_at": "2026-10-14T05:50:00.000Z", "updated_at": "2026-10-14T09:30:00.000Z", "members": [ { "user_id": "coach-ana", "display_name": "Ana Coach", "avatar_url": null }, { "user_id": "client-john", "display_name": "John Client", "avatar_url": null } ], "member_count": 2, "my_role": "MEMBER", "has_unread": true}Member
Section titled “Member”A user’s membership in one conversation. Returned by Conversations_listMembers and Conversations_addMember, and sent as member in member.added.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
user_id |
string | no | The member’s user id. |
display_name |
string | no | The member’s name. Falls back to the user id when Chat has no profile. |
avatar_url |
string | yes | A link to the avatar. |
member_id |
string | no | The id of the membership itself. |
role |
OWNER, ADMIN, MEMBER |
no | The role in this conversation. It decides who owns the content, never what a user may do; permissions come from Chat permissions. |
status |
ACTIVE, LEFT, REMOVED |
no | Whether the user is still a member. |
joined_at |
string | no | When the user joined. |
{ "user_id": "client-john", "display_name": "John Client", "avatar_url": null, "member_id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "role": "MEMBER", "status": "ACTIVE", "joined_at": "2026-10-14T05:55:00.000Z"}UserRef
Section titled “UserRef”A short reference to a user, embedded wherever Chat names someone: the members of a conversation and the sender of a message.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
user_id |
string | no | The user’s id. |
display_name |
string | no | The user’s name. Falls back to the user id when Chat has no profile. |
avatar_url |
string | yes | A link to the avatar. |
{ "user_id": "coach-ana", "display_name": "Ana Coach", "avatar_url": null }Message
Section titled “Message”A message in a conversation. Returned by Messages_list, Messages_send and Messages_edit, and sent as message in message.created and message.updated. See Messages.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
message_id |
string | no | The message’s id. |
conversation_id |
string | no | The conversation it belongs to. |
tenant_id |
string | no | The tenant. |
application_id |
string | no | The application. |
sender_user_id |
string | yes | The sending user. null for a SYSTEM message. |
sender_client_id |
string | yes | Set when a backend client sent the message, on behalf of sender_user_id or as a SYSTEM message. |
sender |
UserRef | yes | The sending user as a reference. null for a SYSTEM message. |
body |
string | no | The text. Empty for a deleted message. |
message_type |
TEXT, SYSTEM, FILE |
no | The kind of message. Only backend clients send SYSTEM. |
reply_to_message_id |
string | yes | The message this one replies to, in the same conversation. |
attachments |
array of Attachment | no | The attached files; empty when there are none. |
status |
ACTIVE, EDITED, DELETED |
no | DELETED marks a tombstone. |
edited_at |
string | yes | When it was last edited. |
deleted_at |
string | yes | When it was deleted. |
created_at |
string | no | When it was sent. |
updated_at |
string | no | When it last changed. |
reactions |
array of Reaction summary | no | One entry per emoji in use; empty when there are none. |
mentioned_user_ids |
array of string | no | The members mentioned. Mentions of people who are not active members are dropped. |
The maximum length of body is 10,000 characters, and a message takes at most 10 attachments. A longer body fails with body_too_long.
{ "message_id": "7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d", "conversation_id": "3f7c2a9e-5b1d-4e8a-9c63-1a2b3c4d5e6f", "tenant_id": "fitness", "application_id": "fitness-app", "sender_user_id": "coach-ana", "sender_client_id": null, "sender": { "user_id": "coach-ana", "display_name": "Ana Coach", "avatar_url": null }, "body": "Squad, 6:30 at the track. Bring water.", "message_type": "TEXT", "reply_to_message_id": null, "attachments": [], "status": "ACTIVE", "edited_at": null, "deleted_at": null, "created_at": "2026-10-14T06:00:00.000Z", "updated_at": "2026-10-14T06:00:00.000Z", "reactions": [{ "emoji": "💪", "count": 1, "reacted_by_me": false }], "mentioned_user_ids": []}Attachment
Section titled “Attachment”A reference to a file. Chat does not store files: file_id points at a file your app keeps elsewhere.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
file_id |
string | no | The id of the file in your file service. |
name |
string | no | The file name. |
mime_type |
string | no | The media type, such as application/pdf. |
size |
number | no | The file size, as you supplied it when sending the message. |
url |
string | yes | A link to the file when one is available. |
{ "file_id": "plan-week-42", "name": "week-42-plan.pdf", "mime_type": "application/pdf", "size": 183204, "url": null}Reaction summary
Section titled “Reaction summary”The reactions on a message, grouped by emoji. It does not list who reacted; the reaction.added and reaction.removed events name the user.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
emoji |
string | no | The emoji. |
count |
number | no | How many members reacted with it. |
reacted_by_me |
boolean | no | Whether the caller reacted with it. |
{ "emoji": "💪", "count": 3, "reacted_by_me": true }Presence status
Section titled “Presence status”A user’s presence. Returned in items by Presence_statuses. See Presence.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
user_id |
string | no | The user. |
status |
online, offline |
no | The current status. |
last_seen_at |
string | yes | When the user last sent a heartbeat. null when never seen or after an explicit offline. |
{ "user_id": "coach-ana", "status": "online", "last_seen_at": "2026-10-14T05:45:00.000Z" }The list response is { "items": [ … ] }. It is not paged, and ids that are not members of the tenant are left out.
Capabilities
Section titled “Capabilities”What the caller may do in a context. Returned by TenantContext_applicationCapabilities and, for the tenant as a whole, TenantContext_tenantCapabilities. Use it to show or hide controls. See Capabilities.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
tenant_id |
string | no | The tenant. |
application_id |
string | yes | The application. null on the tenant-level route. |
principal_type |
user, machine |
no | The kind of token the caller used. |
roles |
array of string | no | The user’s role names in this context. Show them if you like; do not branch on them. |
capabilities |
array of string | no | The Chat permission keys the caller holds, such as messages.send. |
{ "tenant_id": "fitness", "application_id": "fitness-app", "principal_type": "user", "roles": ["client"], "capabilities": ["conversations.read", "messages.read", "messages.send", "messages.update"]}Realtime token
Section titled “Realtime token”The credential for the live event stream. Returned by RealtimeToken_realtimeToken. See Realtime events.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
stream_url |
string | no | The address to open with EventSource. Subscribe-only and opaque. |
expires |
number | no | When the credential expires, in epoch milliseconds, not an ISO string. |
user_id |
string | no | The caller’s user id. |
{ "stream_url": "https://…", "expires": 1791970200000, "user_id": "client-john"}Tenant summary
Section titled “Tenant summary”A tenant the signed-in user belongs to. Returned in items by Me_tenants.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
tenant_id |
string | no | The Identity Server tenant id. |
name |
string | no | The tenant’s name. |
slug |
string | no | The tenant’s short name. |
logo_url |
string | yes | A link to the logo. |
{ "tenant_id": "fitness", "name": "Fitness", "slug": "fitness", "logo_url": null }Application summary
Section titled “Application summary”An application of a tenant. Returned in items by TenantContext_applications.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
application_id |
string | no | The Identity Server application id. |
name |
string | no | The application’s name. |
slug |
string | no | The application’s short name. |
logo_url |
string | yes | A link to the logo. |
type |
PLATFORM, TENANT |
no | PLATFORM for Chat itself, TENANT for your own application. |
chat_enabled |
boolean | no | Whether Chat is switched on for it. |
{ "application_id": "fitness-app", "name": "Fitness app", "slug": "fitness-app", "logo_url": null, "type": "TENANT", "chat_enabled": true}Lists that can be long come back in a page. See Pagination.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
items |
array | no | The objects on this page. |
next_cursor |
string | yes | Pass it as before to get the next, older page. null on the last page. |
Conversations, members and messages come back as a page, and so do the administration lists of members and audit logs. A page holds 50 items by default and at most 100 items. Send the cursor back unchanged; a cursor Chat did not issue fails with invalid_cursor.
{ "items": [ { "member_id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b", "user_id": "client-john", "display_name": "John Client", "avatar_url": null, "role": "MEMBER", "status": "ACTIVE", "joined_at": "2026-10-14T05:55:00.000Z" } ], "next_cursor": null}