Skip to main content
Conversations represent the user’s view of a chat, tracking read states, drafts, notifications, and other personal settings. This page covers the Conversation type and related operations for managing conversation state.

Conversation Type

The Conversation type encapsulates the state of a chat from the current user’s perspective:
message Conversation {
  refs.ChatRef chat_ref = 1;
  // defaults to chat id if no last message (used for sorting)
  // @snowflake<Message>
  fixed64 last_message_id = 2;
  // @snowflake<Message>
  fixed64 last_read_message_id = 3;
  // reserved possible read receipts (last_read_message_id_sent?)
  reserved 4;
  uint32 unread_count = 5;
  optional string draft = 6;
  optional PermissionOverrides permissions = 7;
  bool muted = 8;
}

Fields

chat_ref
ChatRef
Reference identifying this conversation. For direct messages, this references a user ID. For group chats, this references a chat ID
last_message_id
fixed64
Snowflake Message ID of the most recent message in this conversation. If no messages exist yet, this defaults to the chat ID. Used for sorting conversations chronologically
last_read_message_id
fixed64
Snowflake Message ID of the last message the current user has marked as read. Messages after this ID are considered unread
unread_count
uint32
Number of unread messages in this conversation. Calculated as messages after last_read_message_id
draft
string
Unsent message text saved as a draft for this conversation. Allows users to preserve work-in-progress messages
permissions
PermissionOverrides
Custom permission overrides for this specific conversation
muted
bool
Whether the user has muted notifications for this conversation

Permission Overrides

message PermissionOverrides {
  fixed64 pos = 1;
  fixed64 neg = 2;
}
pos
fixed64
Bitfield of permissions to explicitly grant for this conversation
neg
fixed64
Bitfield of permissions to explicitly deny for this conversation

Read States

MarkChatRead

Mark messages as read in a conversation, updating the read position and clearing unread count.
message MarkChatRead {
  refs.ChatRef chat_ref = 1;
  // @snowflake<Message>
  fixed64 message_id = 2;
  optional uint32 read_amount = 3;
}

Parameters

chat_ref
ChatRef
required
Reference to the conversation to update
message_id
fixed64
required
Snowflake Message ID to mark as the last read message. All messages up to and including this ID will be marked as read
read_amount
uint32
Number of messages being marked as read (for analytics/tracking purposes)

Response

Returns empty on success. The server updates the Conversation object:
  • Sets last_read_message_id to the provided message_id
  • Recalculates unread_count to 0 (or remaining unread messages if newer messages exist)

Behavior

  • Marking a message as read implicitly marks all earlier messages as read
  • If new messages arrive after marking as read, unread_count increments accordingly
  • Read states are per-user and don’t affect other participants

Typing Indicators

SetTyping

Indicate whether the current user is typing in a conversation.
message SetTyping {
  refs.ChatRef chat_ref = 1;
  bool typing = 2;
}

Parameters

chat_ref
ChatRef
required
Reference to the conversation where typing is occurring
typing
bool
required
true to indicate the user is typing, false to indicate they stopped

Response

Returns empty on success.

Behavior

  • Typing indicators are ephemeral and typically expire after a few seconds of inactivity
  • Other participants in the conversation receive real-time updates about typing status
  • Sending a message automatically clears the typing indicator
  • Clients should send typing = false when the user clears the input field or leaves the conversation

Best Practices

  • Send typing = true when the user starts typing (debounced to avoid excessive updates)
  • Send typing = false when the user stops typing for ~2-3 seconds
  • Clear typing state when sending a message
  • Don’t spam typing updates on every keystroke

Chat Invites

Invites allow users to join group chats via a shareable code.

CreateChatInvite

Generate an invite code for a group chat.
message CreateChatInvite {
  refs.ChatRef chat_ref = 1;
  optional fixed64 expires_at = 2;
  optional uint32 max_uses = 3;
}

Parameters

chat_ref
ChatRef
required
Reference to the group chat to create an invite for
expires_at
fixed64
Unix timestamp (in milliseconds) when the invite expires. If not provided, the invite never expires
max_uses
uint32
Maximum number of times the invite can be used. If not provided, unlimited uses are allowed

Response

Returns an auth.CreatedInvite object containing the invite code and metadata.

Permissions

  • Only group chat owners can create invites
  • Direct messages don’t support invites

ListChatInvites

Retrieve all active invites for a group chat.
message ListChatInvites {
  refs.ChatRef chat_ref = 1;
}

Parameters

chat_ref
ChatRef
required
Reference to the group chat

Response

Returns an auth.InviteList object containing all active invites for the chat.

DeleteChatInvite

Revoke an invite code, preventing further uses.
message DeleteChatInvite {
  string code = 1;
}

Parameters

code
string
required
The invite code to delete/revoke

Response

Returns empty on success.

Behavior

  • Deleted invites can no longer be used to join the chat
  • Users who already joined via the invite remain in the group
  • Only the invite creator or group owner can delete invites

Conversation State Management

Sorting Conversations

Use last_message_id to sort conversations by most recent activity:
sorted_conversations = conversations.sort_by(|c| c.last_message_id).reverse()
Since last_message_id defaults to the chat ID when no messages exist, new conversations without messages still sort correctly.

Unread Tracking

The unread_count field provides an immediate count of unread messages:
  • Display badge with count on conversation list items
  • Bold or highlight conversations with unread_count > 0
  • Clear count by calling MarkChatRead with the latest message ID

Draft Management

The draft field persists unsent message text:
  1. Save draft text to the Conversation when the user types
  2. Restore draft when opening the conversation
  3. Clear draft when sending a message

Muting Conversations

The muted field controls notifications:
  • When muted = true, suppress notifications for new messages
  • Still increment unread_count and show visual indicators
  • Allow users to toggle mute status per conversation

Build docs developers (and LLMs) love