4.3 KiB
4.3 KiB
Realtime WebSocket API
WebSocket endpoint:
GET /api/v1/realtime/ws?token=<access_token>
Authentication:
- Pass a valid access token as query parameter
token. - If token is missing/invalid, server closes with
1008(policy violation).
1. Message envelope
All incoming and outgoing events use the same envelope:
{
"event": "event_name",
"payload": {},
"timestamp": "2026-03-08T12:00:00Z"
}
timestamp is present in outgoing events from the server.
2. Incoming events (client -> server)
2.1 ping
{
"event": "ping",
"payload": {}
}
Server response: pong
2.2 send_message
{
"event": "send_message",
"payload": {
"chat_id": 10,
"type": "text",
"text": "Hello",
"temp_id": "tmp-1",
"client_message_id": "client-msg-1",
"reply_to_message_id": null
}
}
Supported type values:
text,image,video,audio,voice,file,circle_video
2.3 typing_start / typing_stop
{
"event": "typing_start",
"payload": {
"chat_id": 10
}
}
2.4 message_delivered / message_read
{
"event": "message_read",
"payload": {
"chat_id": 10,
"message_id": 150
}
}
3. Outgoing events (server -> client)
3.1 connect
Sent after successful websocket registration:
{
"event": "connect",
"payload": {
"connection_id": "uuid"
},
"timestamp": "2026-03-08T12:00:00Z"
}
3.2 pong
Response to ping:
{
"event": "pong",
"payload": {},
"timestamp": "2026-03-08T12:00:00Z"
}
3.3 receive_message
{
"event": "receive_message",
"payload": {
"chat_id": 10,
"message": {
"id": 123,
"chat_id": 10,
"sender_id": 1,
"reply_to_message_id": null,
"forwarded_from_message_id": null,
"type": "text",
"text": "Hello",
"created_at": "2026-03-08T12:00:00Z",
"updated_at": "2026-03-08T12:00:00Z"
},
"temp_id": "tmp-1",
"client_message_id": "client-msg-1",
"sender_id": 1
},
"timestamp": "2026-03-08T12:00:00Z"
}
3.4 Typing events
typing_start and typing_stop:
{
"event": "typing_start",
"payload": {
"chat_id": 10,
"user_id": 2
},
"timestamp": "2026-03-08T12:00:00Z"
}
3.5 Delivery/read events
message_delivered and message_read:
{
"event": "message_read",
"payload": {
"chat_id": 10,
"message_id": 150,
"user_id": 2,
"last_delivered_message_id": 150,
"last_read_message_id": 150
},
"timestamp": "2026-03-08T12:00:00Z"
}
3.6 Presence events
user_online
{
"event": "user_online",
"payload": {
"chat_id": 10,
"user_id": 2,
"is_online": true
},
"timestamp": "2026-03-08T12:00:00Z"
}
user_offline
{
"event": "user_offline",
"payload": {
"chat_id": 10,
"user_id": 2,
"is_online": false,
"last_seen_at": "2026-03-08T12:00:00Z"
},
"timestamp": "2026-03-08T12:00:00Z"
}
3.7 chat_updated
Sent when chat metadata/membership/roles/title changes:
{
"event": "chat_updated",
"payload": {
"chat_id": 10
},
"timestamp": "2026-03-08T12:00:00Z"
}
3.8 error
Validation/runtime error during WS processing:
{
"event": "error",
"payload": {
"detail": "Invalid event payload"
},
"timestamp": "2026-03-08T12:00:00Z"
}
4. Disconnect behavior
- On disconnect, server unregisters connection.
- When last connection for a user closes, server marks user offline and sends
user_offlineto related chats.
5. Practical client recommendations
- Keep one active socket per tab/session.
- Send periodic
pingand expectpong. - Reconnect with exponential backoff.
- On
chat_updated, refresh chat metadata via REST (GET /api/v1/chatsorGET /api/v1/chats/{chat_id}). - On reconnect/visibility restore, reconcile state by reloading already-opened chats/messages via REST
to recover missed
message_deleted/delivery updates after transient disconnects or backend restarts. - For browser notifications, mentions (
@username) should be treated as high-priority and can bypass per-chat-type notification toggles in client preferences. - Use REST message history endpoints for pagination; WS is realtime transport, not history source.