Skip to content

WebSocket connections

A WebSocket keeps a persistent, two-way channel open between client and server. ChannelX uses it to push platform events as they happen, so a dashboard or mobile client can update live without reloading. To connect, you authenticate with a token and subscribe to the channel.

Experimental

This feature is experimental and the details may change between releases. Backward compatibility isn't guaranteed, so always build against the latest version.

Why use a WebSocket

A WebSocket delivers real-time updates, which makes it ideal for clients such as an Android or iOS SDK. The dashboard reflects new messages and status changes instantly, improving the agent experience and productivity.

Connecting

Open a connection to wss://<your-installation-url>/cable using an authentication PubSub token from ChannelX. A PubSub token authenticates a client to the publish-subscribe service so it can subscribe to events.

There are two token types:

  • User PubSub token — carries agent/admin privileges and receives every event listed below. Retrieve it from the Profile API.
  • Contact PubSub token — generated per contact session. It only grants events for that session, such as conversation.created, conversation.status_changed, message.created, message.updated, conversation.typing_on, conversation.typing_off, and presence.update. When a contact is created through the public APIs, its pubsub_token is returned in the response.

Tokens can rotate

Depending on your installation, tokens may be rotated regularly. Always connect with the current token, and treat any PubSub token as a secret — it grants real-time access to conversation data.

To subscribe, send a subscribe command with your pubSubToken, accountId, and (for a user token) userId:

const stringify = (payload = {}) => JSON.stringify(payload);

const pubSubToken = "<contact/user-pub-sub-token>";
const accountId = "<your-account-id-in-integer>";
const userId = "<user-id-in-integer-if-using-user-token>";
const connection = new WebSocket("wss://<your-installation-url>/cable");

connection.send(
  stringify({
    command: "subscribe",
    identifier: stringify({
      channel: "RoomChannel",
      pubsub_token: pubSubToken,
      account_id: accountId,
      user_id: userId,
    }),
  })
);

Publishing presence

To keep a user shown as online, send a presence update roughly every 30 seconds. For an agent or admin:

const userPayload = stringify({
  command: "message",
  identifier: stringify({
    channel: "RoomChannel",
    pubsub_token: "<user-pubsub-token>",
    account_id: accountId,
    user_id: userId,
  }),
  data: stringify({ action: "update_presence" }),
});

connection.send(userPayload);

For a contact, send the same update_presence action with just the channel and contact PubSub token in the identifier.

Payload objects

Events carry one of a few object types:

  • Conversation — id, inbox, status, channel, the contact_inbox link, messages, and a meta block with sender and assignee.
  • Contact — id, name, email, phone number, identifier, thumbnail, and attribute objects.
  • User — id, name, available name, avatar, and availability status.
  • Message — id, content, type, content attributes, sender, and timestamps.
  • Notification — id, type, the primary actor, read state, and timestamps.

Each event includes an identifier (channel, token, account, user) and a message carrying the event name and its data.

Event types

Event Sent to Triggered when
conversation.created agent/admin, contact A new conversation starts.
conversation.read agent/admin A contact reads a message.
message.created agent/admin, contact A new message is created.
message.updated agent/admin, contact A message is updated.
conversation.status_changed agent/admin, contact A conversation's status changes.
conversation.typing_on agent/admin, contact A contact or agent starts typing (is_private marks a note).
conversation.typing_off agent/admin, contact Typing stops.
assignee.changed agent/admin The assigned agent changes.
team.changed agent/admin The assigned team changes.
conversation.contact_changed agent/admin Two contacts merge and their conversations consolidate.
contact.created agent/admin A contact is created.
contact.updated agent/admin A contact is updated.
presence.update agent/admin, contact Availability status changes. Contacts don't see other contacts' status.
notification_created agent/admin A notification is created.

Each event payload follows the shape:

{
  "message": {
    "event": "message.created",
    "data": { /* the relevant object */ }
  }
}