Skip to main content
PingBack’s real-time layer is built on Socket.IO with a Redis backplane. All live features — new messages, typing indicators, delivery receipts, and agent status — flow through this connection.
Socket.IO supports both WebSocket and long-polling transports. PingBack uses WebSocket by default and falls back to polling automatically when WebSocket is unavailable.

Connect

Connect to https://api.pingback.live and pass your business_id in the auth handshake object. PingBack rejects connections that do not include a business_id.
import { io } from "socket.io-client";

const socket = io("https://api.pingback.live", {
  auth: {
    business_id: "YOUR_BUSINESS_ID",
  },
  transports: ["websocket", "polling"],
});

socket.on("connect", () => {
  console.log("Connected:", socket.id);
});

Room system

PingBack uses rooms to scope events to the right audience. Join a room to start receiving its events.
RoomPurpose
business_{business_id}Org-wide events for your entire workspace.
conversation_{conversation_id}Events scoped to a single conversation.
To join a conversation room, emit join_conversation:
socket.emit("join_conversation", { conversation_id: 42 });

Events to listen for (server → client)

These events are emitted by the server. Listen for them in your client.

new_message

Fires when any participant in the conversation sends a message. Payload:
FieldTypeDescription
idnumberMessage ID.
contentstringMessage text (or file URL for attachments).
sender_typestring"customer" or "agent".
conversation_idnumberThe conversation this message belongs to.
created_atstringISO 8601 timestamp.

typing

Fires when a participant starts or stops typing. Payload: { conversation_id, user_id, is_typing }

delivered

Fires when a message is marked as delivered. Payload: { message_id, delivered_at }

read

Fires when a message is marked as read. Payload: { message_id, read_at }

agent_status_changed

Fires when an agent’s online status changes. Payload: { agent_id, status }

conversation_assigned

Fires when a conversation is assigned to an agent. Payload: { conversation_id, assigned_by }

Events to emit (client → server)

These events are sent from your client to PingBack.

join_conversation

Join a conversation room to receive its events. Payload: { conversation_id: number }

client_message

Send a message from the customer widget. PingBack creates a new conversation automatically if conversation_id is omitted. Payload:
FieldTypeRequiredDescription
contentstringYesThe message text.
conversation_idnumberNoInclude to continue an existing conversation.
customer_dataobjectYes{ name: string, email: string } — identifies the customer.

typing

Broadcast a typing indicator to all participants in the conversation. Payload: { conversation_id: number, user_id: number, is_typing: boolean }

Complete integration example

The example below shows how to connect, join a conversation, send messages, and handle incoming events in a customer-facing widget.
import { io } from "socket.io-client";

const socket = io("https://api.pingback.live", {
  auth: { business_id: "YOUR_BUSINESS_ID" },
  transports: ["websocket", "polling"],
});

// Track the active conversation
let conversationId = null;

// Join an existing conversation (if resuming a session)
function joinConversation(id) {
  conversationId = id;
  socket.emit("join_conversation", { conversation_id: id });
}

// Send a message from the customer
function sendMessage(text) {
  socket.emit("client_message", {
    content: text,
    conversation_id: conversationId, // omit to start a new conversation
    customer_data: {
      name: "Jane Smith",
      email: "jane@example.com",
    },
  });
}

// Send a typing indicator
function setTyping(isTyping) {
  socket.emit("typing", {
    conversation_id: conversationId,
    user_id: "customer",
    is_typing: isTyping,
  });
}

// Listen for new messages
socket.on("new_message", (message) => {
  console.log(`[${message.sender_type}] ${message.content}`);
  // Update conversationId from the first reply
  if (!conversationId) {
    conversationId = message.conversation_id;
  }
});

// Listen for typing indicators
socket.on("typing", ({ user_id, is_typing }) => {
  console.log(`User ${user_id} is ${is_typing ? "typing..." : "done typing"}`);
});

// Listen for delivery and read receipts
socket.on("delivered", ({ message_id, delivered_at }) => {
  console.log(`Message ${message_id} delivered at ${delivered_at}`);
});

socket.on("read", ({ message_id, read_at }) => {
  console.log(`Message ${message_id} read at ${read_at}`);
});