SupportWhale
← All help articles
API & integrations

Realtime event contract

Socket.IO subscriptions, authorization and reconnection.

Last updated · Oct 23, 2026

Authentication boundary

Socket.IO is the browser and native app transport, not an API-key endpoint. Bearer API keys are rejected. Agents use their authenticated session; visitors use the widget-issued visitor token. Origin and organization/conversation access are checked on connection and subscription. Use the supported REST integration API for server integrations; never reuse a visitor token as an agent credential.

Client events

site.subscribe takes a widget/legacy site ID and acknowledges { ok: true } or { ok: false }. Agent sessions only; subscribes to the organization’s widget aliases. site.unsubscribe removes that subscription.

conversation.subscribe takes a conversation ID and acknowledges { ok: true } or { ok: false }. Visitors can only subscribe to their own conversation; agents need organization access. conversation.unsubscribe takes the same ID.

presence.subscribe takes an array of at most 100 conversation IDs, replaces the previous presence subscription and acknowledges { ok: true } or { ok: false }. Agent sessions only; every conversation is authorized.

typing takes { conversationId, typing: boolean }. Authorized recipients receive { conversationId, kind: "agent" | "visitor", typing: boolean }. No durable delivery is promised for typing.

Server events

message.created delivers the message view; conversation.updated delivers the authorized conversation view. Private notes go only to agent rooms, and visitor conversation views omit internal AI fields. presence carries widget agent availability; conversation.presence carries visitor presence for the conversation. Presence is transient and lease-based, not proof that a customer has read a message.

Reconnect and recovery

Re-establish subscriptions after reconnect and load persisted messages through the authenticated HTTP API. Do not assume exactly-once delivery: deduplicate messages by id and reconcile conversation state. Subscription rejection is not an empty conversation. Session revocation or loss of access disconnects the socket. Never log session cookies or visitor tokens.

Payload fields

message.created contains _id, conversationId, senderType, body, internal and createdAt, plus attachments with id, filename, contentType and size. conversation.created and conversation.updated carry _id, status and lastMessageAt; agent views can include contact, tags, assigneeId and unreadCount. Treat optional fields as optional, and ignore new fields.

conversation.read and conversation.delivered carry conversationId, kind and deliveredAt; read events also carry readAt. Times are ISO timestamps when present. presence carries websiteId, status (online/offline/unknown), online (boolean or null) and optional lastSeenAt. conversation.presence has the same presence fields with conversationId instead of websiteId. Message delivery/read receipts are distinct from socket connection and typing state.

Need a hand? Contact us →