Skip to content

Realtime WebSocket Protocol

Chatto exposes realtime updates at GET /api/realtime using binary protobuf frames from chatto.realtime.v1.

Realtime frames are documented separately from ConnectRPC services because they are exchanged over a long-lived WebSocket session rather than /api/connect RPC methods.

Asset-deleted signal.

Remove local attachment state by asset_id. When the owning message is known, clients can refetch that message through MessageService.GetMessage or refetch the timeline window.

FieldTypeDescription
room_idoptional stringRoom containing the message that owned the asset, when known.
asset_idstringAsset ID.

Asset-processing signal.

Message attachments are message-owned subresources. When message_event_id is known, refetch message state with MessageService.GetMessage or MessageService.BatchGetMessages; otherwise refetch the affected attachment list or timeline window.

FieldTypeDescription
room_idoptional stringRoom containing the message that owns the asset, when known.
asset_idstringAsset ID.
message_event_idoptional stringEvent ID of the message that owns the asset, when known.

Voice-call state signal.

Hydrate current room-scoped call state with VoiceCallService.GetActiveCall or VoiceCallService.BatchGetActiveCalls. Compare call_id to ignore stale transitions from a previous call in the same room.

FieldTypeDescription
room_idstringRoom containing the call.
call_idstringCall ID.
sourceRealtimeCallEventSourceSource that produced the call transition.

Client-to-server frame for Chatto’s protobuf WebSocket realtime protocol.

Clients send binary protobuf frames to /api/realtime. The first frame must be hello; after the server replies with hello, clients send subscribe_events to start the authenticated live event stream.

FieldTypeDescription
frame.helloRealtimeClientHelloOpens the protocol session and optionally carries a bearer token.
frame.subscribe_eventsRealtimeSubscribeEventsStarts the caller’s authorized live-event stream.
frame.pingRealtimePingApplication-level ping. The server replies with pong.

Initial client hello.

FieldTypeDescription
protocol_versionuint32Protocol version requested by the client. The current version is 1.
bearer_tokenoptional stringOptional bearer token. When present, it takes precedence over cookie auth.

Close instruction sent before the socket is closed when possible.

FieldTypeDescription
codestringStable machine-readable close code.
messagestringHuman-readable diagnostic message.
reconnectboolTrue when the client should reconnect after a delay.
retry_after_msuint32Suggested reconnect delay in milliseconds.

Protocol error.

FieldTypeDescription
codestringStable machine-readable error code.
messagestringHuman-readable diagnostic message.
fatalboolTrue when the server will close the socket after sending this error.

One authorized live event delivered over the realtime WebSocket.

Realtime events are invalidation signals first: payloads carry stable IDs and small inline hints, while durable resource state is hydrated through chatto.api.v1 ConnectRPC services. Event-specific messages document the intended hydration path when a referenced resource may need refreshing.

FieldTypeDescription
idstringStable event ID.
created_atgoogle.protobuf.TimestampTime the event was created.
actor_idoptional stringUser or system actor that caused the event, when known.
event.message_postedRealtimeMessagePostedEventA message was posted in a room or thread.
event.message_editedRealtimeMessageEditedEventA message body or renderable metadata changed.
event.message_retractedRealtimeMessageRetractedEventA message was retracted.
event.reaction_addedRealtimeReactionEventA user added a reaction to a message.
event.reaction_removedRealtimeReactionEventA user removed a reaction from a message.
event.user_typingRealtimeTypingEventA user is typing in a room or thread.
event.presence_changedRealtimePresenceChangedEventA user’s live presence changed.
event.room_createdRealtimeRoomEventA room was created.
event.room_updatedRealtimeRoomEventA room’s profile or settings changed.
event.room_deletedRealtimeRoomEventA room was deleted.
event.room_archivedRealtimeRoomEventA room was archived.
event.room_unarchivedRealtimeRoomEventA room was restored from the archive.
event.user_joined_roomRealtimeRoomEventA user joined a room visible to the current user.
event.user_left_roomRealtimeRoomEventA user left a room visible to the current user.
event.room_universal_changedRealtimeRoomUniversalChangedEventA room’s universal visibility flag changed.
event.notification_createdRealtimeNotificationCreatedEventA notification was created for the current user.
event.notification_dismissedRealtimeNotificationDismissedEventA notification was dismissed for the current user.
event.notification_level_changedRealtimeNotificationLevelChangedEventThe current user’s notification level changed.
event.thread_follow_changedRealtimeThreadFollowChangedEventThe current user’s thread follow state changed.
event.room_marked_as_readRealtimeRoomMarkedAsReadEventThe current user’s room read state changed.
event.thread_createdRealtimeThreadCreatedEventA thread was created in a room visible to the current user.
event.server_updatedRealtimeServerUpdatedEventThe server profile/config changed.
event.user_profile_updatedRealtimeUserProfileUpdatedEventA user profile changed.
event.user_custom_status_setRealtimeUserCustomStatusSetEventA user’s custom status was set or changed.
event.user_custom_status_clearedRealtimeUserCustomStatusClearedEventA user’s custom status was cleared.
event.server_user_preferences_updatedRealtimeServerUserPreferencesUpdatedEventThe current user’s display preferences changed.
event.room_groups_updatedRealtimeRoomGroupsUpdatedEventRoom-group layout changed.
event.server_member_deletedRealtimeServerMemberDeletedEventA server member was deleted.
event.asset_processing_startedRealtimeAssetProcessingEventAsset processing started for a message attachment.
event.asset_processing_succeededRealtimeAssetProcessingEventAsset processing completed successfully for a message attachment.
event.asset_processing_failedRealtimeAssetProcessingEventAsset processing failed for a message attachment.
event.asset_deletedRealtimeAssetDeletedEventAn asset attached to a message was deleted.
event.call_startedRealtimeCallEventA voice call started in a room.
event.call_participant_joinedRealtimeCallEventA participant joined a voice call.
event.call_participant_leftRealtimeCallEventA participant left a voice call.
event.call_endedRealtimeCallEventA voice call ended.
event.mention_notificationRealtimeMentionNotificationEventThe current user was mentioned in a room.
event.new_direct_message_notificationRealtimeNewDirectMessageNotificationEventThe current user received a new direct message.
event.session_terminatedRealtimeSessionTerminatedEventThe current user’s session was terminated.

Application-level heartbeat.

FieldTypeDescription
idstringStable event ID for this heartbeat.
created_atgoogle.protobuf.TimestampTime the heartbeat was emitted.

Mention attention signal for the connected user.

Inline names are display hints. Hydrate referenced rooms through RoomDirectoryService.BatchGetRooms and users through UserService.BatchGetUsers when local caches are missing or stale.

FieldTypeDescription
room_idstringRoom where the mention occurred.
actor_user_idstringAuthor user ID.
room_nameoptional stringDisplay name of the room where the mention occurred, when hydrated for the caller.
actor_display_nameoptional stringDisplay name of the author who mentioned the connected user, when hydrated.

Message-edited signal.

Refresh the affected timeline window with RoomService.GetRoomEventsAround for room messages, or ThreadService.GetThreadEventsAround when the local message belongs to a thread.

FieldTypeDescription
room_idstringRoom containing the message.
message_event_idstringEvent ID of the edited message.

Message-posted signal.

Hydrate the affected timeline with RoomService.GetRoomEventsAround for room messages, or ThreadService.GetThreadEventsAround when thread_root_event_id is set.

FieldTypeDescription
room_idstringRoom containing the message.
message_event_idstringEvent ID of the posted message.
thread_root_event_idoptional stringRoot message event ID when the message was posted in a thread.

Message-retracted signal.

Refresh or patch the affected timeline window with RoomService.GetRoomEventsAround for room messages, or ThreadService.GetThreadEventsAround when the local message belongs to a thread.

FieldTypeDescription
room_idstringRoom containing the message.
message_event_idstringEvent ID of the retracted message.
reasonoptional stringRetraction reason, when one was supplied.

New-DM attention signal for the connected user.

Inline names and avatar URLs are display hints. Hydrate the DM room through RoomDirectoryService.GetRoom or RoomDirectoryService.BatchGetRooms, and the sender through UserService.GetUser or UserService.BatchGetUsers when local caches are missing or stale.

FieldTypeDescription
room_idstringDM room ID.
sender_idstringSender user ID.
sender_display_nameoptional stringDisplay name of the sender, when hydrated.
sender_avatar_urloptional stringAvatar URL of the sender, when one is available.
conversation_nameoptional stringDisplay name for the DM conversation from the connected user’s perspective, when hydrated.

Notification-created signal for the connected user.

Hydrate full notification rows with NotificationService.GetNotification or NotificationService.BatchGetNotifications. Use RoomService or ThreadService anchor reads when event_id or in_reply_to_id must be opened in context.

FieldTypeDescription
notification_idstringNotification ID.
room_idoptional stringRoom associated with the notification, when the notification navigates to a room.
event_idoptional stringEvent ID associated with the notification, when the notification navigates to an event.
in_reply_to_idoptional stringParent event ID for reply notifications, when known.
silentboolTrue when the notification should not alert.

Notification-dismissed signal for the connected user.

Remove the local notification row by ID. A later singular notification read returns NOT_FOUND; batch reads omit dismissed or missing notifications.

FieldTypeDescription
notification_idstringNotification ID.

Notification-level signal for the connected user.

The updated level is inline. Use NotificationPreferencesService.GetRoomNotificationPreference when clients need the complete preference resource.

FieldTypeDescription
room_idstringRoom whose notification level changed.
levelchatto.api.v1.NotificationLevelExplicit room notification level.
effective_levelchatto.api.v1.NotificationLevelEffective notification level after defaults are applied.

Application-level ping.

FieldTypeDescription
noncestringClient-chosen opaque value echoed in the pong.

Application-level pong.

FieldTypeDescription
noncestringEcho of the ping nonce.

Presence-changed signal.

The latest presence status is inline. Use UserService.GetUser when the surrounding user profile or custom status also needs refreshing.

FieldTypeDescription
user_idstringUser whose presence changed.
statuschatto.api.v1.PresenceStatusLatest presence status.

Reaction signal.

Refresh or patch the affected message in its timeline window. Use RoomService.GetRoomEventsAround for room messages, or ThreadService.GetThreadEventsAround when the local message belongs to a thread. message_event_id is canonical: reactions made through a channel echo of a thread reply report the original reply event ID. Clients that show channel echoes should also refresh or patch visible echo rows whose echo_of_event_id matches this ID.

FieldTypeDescription
room_idstringRoom containing the reacted-to message.
message_event_idstringCanonical event ID of the reacted-to message.
emojistringReaction emoji.

Room lifecycle or membership signal.

Hydrate visible room state with RoomDirectoryService.GetRoom or RoomDirectoryService.BatchGetRooms. Unknown/deleted rooms return NOT_FOUND from singular reads, hidden rooms return PERMISSION_DENIED, and batch reads omit unknown, deleted, hidden, and inaccessible rooms.

FieldTypeDescription
room_idstringRoom affected by the event.

Room-group layout signal.

Refetch room-group layout with RoomDirectoryService.ListRoomGroups. If a client already knows specific group IDs, it can use RoomDirectoryService.GetRoomGroup or RoomDirectoryService.BatchGetRoomGroups.

FieldTypeDescription
changedboolAlways true; present for event-bus compatibility.

Room-read signal for the connected user.

This is a current-user read-state invalidation signal. Clients can patch local unread state for the room; no separate hydration is normally needed.

FieldTypeDescription
room_idstringRoom marked read.

Room universal-visibility signal.

The latest universal flag is inline. Hydrate the rest of the visible room with RoomDirectoryService.GetRoom or RoomDirectoryService.BatchGetRooms.

FieldTypeDescription
room_idstringRoom whose universal setting changed.
universalboolLatest universal setting.

Server-to-client frame for Chatto’s protobuf WebSocket realtime protocol.

FieldTypeDescription
frame.helloRealtimeServerHelloConfirms protocol version, server version, and capabilities.
frame.subscribedRealtimeSubscribedConfirms the live-event stream has started.
frame.eventRealtimeEventEnvelopeA live event authorized for the connected user.
frame.heartbeatRealtimeHeartbeatApplication-level heartbeat used for liveness checks.
frame.errorRealtimeErrorProtocol or authorization error.
frame.closeRealtimeCloseServer-requested close with reconnect guidance.
frame.pongRealtimePongReply to a client ping.

Initial server hello.

FieldTypeDescription
protocol_versionuint32Protocol version accepted by the server.
server_versionstringChatto server software version.
heartbeat_interval_secondsuint32Approximate heartbeat interval clients should expect.
capabilitiesrepeated stringStable protocol capability keys supported by this server. Current keys: chatto.realtime.events.live.v1, chatto.realtime.heartbeat.v1, and chatto.realtime.ping.v1.

Server-member deleted signal.

Remove or invalidate local member/user rows for user_id. Admin clients can hydrate remaining member rows through AdminUserService.GetMember or AdminUserService.BatchGetMembers.

FieldTypeDescription
user_idstringDeleted user ID.

Server-profile signal.

Public server profile fields are inline. Use ServerDiscoveryService.GetServer for public metadata and ServerService.GetMotd for the authenticated MOTD.

FieldTypeDescription
namestringServer display name.
descriptionstringServer description.
logo_urloptional stringServer logo URL, when configured.
banner_urloptional stringServer banner URL, when configured.

User display-preferences signal for the connected user.

The updated display preferences are inline for the connected user.

FieldTypeDescription
timezoneoptional stringIANA timezone name, when the user has selected a fixed timezone.
time_formatchatto.api.v1.TimeFormatPreferred time display format.

Session-terminated signal for the connected user’s current session.

FieldTypeDescription
reasonstringTermination reason.

Request to start the caller’s authorized live event stream.

Confirms event streaming has started.

Thread-created signal.

Hydrate the new thread with ThreadService.GetThreadEventsAround using thread_root_event_id as the anchor.

FieldTypeDescription
room_idstringRoom containing the thread.
thread_root_event_idstringRoot message event ID that identifies the thread.

Thread-follow signal for the connected user.

The updated follow state is inline. Use ThreadService.GetThreadEvents or ThreadService.GetThreadEventsAround when the thread itself needs refreshing.

FieldTypeDescription
room_idstringRoom containing the thread.
thread_root_event_idstringRoot message event ID of the thread.
followingboolTrue when the user now follows the thread.

Typing signal.

This is an ephemeral signal. room_id and thread_root_event_id identify where to display typing state; clients normally do not hydrate it.

FieldTypeDescription
room_idstringRoom where the actor is typing.
thread_root_event_idoptional stringThread root event ID when the actor is typing in a thread.

User-custom-status cleared signal.

Clear local custom status for user_id. Use UserService.GetUser when clients need to refresh the complete user profile.

FieldTypeDescription
user_idstringUser whose status was cleared.

User-custom-status set signal.

The latest custom status is inline. Use UserService.GetUser when clients need to refresh the complete user profile.

FieldTypeDescription
user_idstringUser whose status changed.
emojistringEmoji part of the status.
textstringText part of the status.
expires_atgoogle.protobuf.TimestampExpiration time, when the status expires automatically.

User-profile signal.

Basic profile fields are inline. Use UserService.GetUser or UserService.BatchGetUsers for complete user-profile hydration.

FieldTypeDescription
user_idstringUser whose profile changed.
loginstringLogin name.
display_namestringDisplay name.
avatar_urloptional stringAvatar URL, when the user has an avatar.

Source that produced a realtime voice-call transition.

NameNumberDescription
REALTIME_CALL_EVENT_SOURCE_UNSPECIFIED0No call event source was specified.
REALTIME_CALL_EVENT_SOURCE_USER1The user explicitly requested the transition through Chatto.
REALTIME_CALL_EVENT_SOURCE_LIVEKIT2LiveKit reported the transition through a webhook.
REALTIME_CALL_EVENT_SOURCE_RECONCILIATION3Chatto reconciled its local state against LiveKit’s current room state.