Realtime
Pushes and actions
What the server sends you over the socket, and what you can send it.
Server → client pushes
Every push about a chat carries chat_id and seq: the chat's last_seq after the change. Clients apply a state push only if its seq ≥ the last one applied for that chat; incoming_event follows the gap rules in Resume and gap detection.
| Push | To | Payload | Sent when |
|---|---|---|---|
incoming_chat |
agents who can see it; the visitor | {chat_id, seq, chat: ChatSummary} (visitor: CustomerChat) |
a thread starts: new chat, visitor resume, agent resume chat, agent start_chat from Traffic |
incoming_event |
agents who can see the chat; the visitor if visibility = all |
{chat_id, seq, thread_id, event: ChatEvent} |
any event: message, note, file, system message |
user_added_to_chat |
agents; visitor | {chat_id, seq, thread: Thread, agent_id} (visitor also gets agent: AgentPublic) |
assignment: router picks an agent, assign chat, queue pick |
chat_transferred |
agents; visitor | {chat_id, seq, thread: Thread, transferred_to: {type, id}, queue: QueueInfo|null} |
transfer_chat, auto-transfer after 3 min unanswered, 30 s agent-disconnect reassignment |
chat_deactivated |
agents; visitor | {chat_id, seq, thread: Thread, reason} reason ∈ agent, customer, inactivity, banned |
thread closed |
thread_tagged / thread_untagged |
agents | {chat_id, seq, thread: Thread, tag_id} |
tag added / removed |
thread_updated |
agents | {chat_id, seq, thread: Thread} |
any other thread change: active ↔ inactive, queued → unassigned (customer left the queue) |
incoming_sneak_peek |
agents | {chat_id, seq, text} |
visitor typing; text may be "" (typing, nothing yet) |
incoming_typing_indicator |
agents; visitor | {chat_id, seq, author_id, is_typing} |
agents: visitor stopped (false); visitor: an agent started/stopped |
events_marked_as_delivered |
agents; visitor | {chat_id, seq, watermark: Watermark} (visitor: agents_watermark) |
a participant's delivered_seq rose |
events_marked_as_seen |
agents; visitor | same | a participant's seen_seq rose |
queue_positions_updated |
visitor | {chat_id, seq, queue: QueueInfo} |
position or wait estimate changed |
routing_status_set |
agents | {agent_id, status} |
an agent's status changed, including offline 30 s after their last socket closed |
availability_updated |
visitor | {online} |
the visitor's group goes from nobody accepting to somebody, or back |
customer_visit_started / customer_visit_ended |
agents (Traffic) | {visitor: Visitor} / {customer_id} |
visitor socket opened / last one closed for 60 s |
customer_page_updated |
agents (Traffic, open chat) | {customer_id, page: PageView} |
visitor sent update_customer_page |
customer_updated |
agents | {customer: Customer} |
name, email, session fields, ban changed |
Agents get chats in their groups (group 0 = all) plus their own; bots get only chats assigned to them; a visitor gets only their own chat, and never notes (visibility = agents), tag IDs or other agents' watermarks.
Client → server actions
| Action | Who | Payload | Response payload |
|---|---|---|---|
login |
all, first frame | {resume?: {<chat_id>: last_seq}} (≤ 100 chats) |
agents: {me: Agent, server_time, heartbeat_s: 25, resume}; visitors: {customer_id, chat: CustomerChat|null, online, server_time, heartbeat_s: 25, resume} |
send_event |
agents, bots, visitors | {chat_id, client_message_id, event: {type: "message", text, visibility?} | {type: "file", attachment_id, visibility?}} |
{event: ChatEvent, duplicate: bool} |
send_typing_indicator |
agents, bots, visitors | {chat_id, is_typing} |
{} |
send_sneak_peek |
visitors | {chat_id, sneak_peek_text} (≤ 4000 chars) |
{} |
mark_events_as_delivered |
agents, visitors | {chat_id, delivered_up_to_seq} |
{watermark} |
mark_events_as_seen |
agents, visitors | {chat_id, seen_up_to_seq} (also raises delivered) |
{watermark} |
set_routing_status |
agents, bots | {status: accepting_chats | not_accepting_chats} |
{agent: Agent} |
update_customer_page |
visitors | {url, title, referrer?} |
{} |
ping |
all | {} |
{} (action pong) |
Everything else (accept, transfer, tag, close, resume, ban, uploads) is done with API methods; the result arrives on every socket as a push.
Watermarks only move up; a lower value is accepted and ignored. Visitor send_event forces visibility: all. Agents send to chats as send_event allows.