> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pingback.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Real-time Messaging

> PingBack uses Socket.IO for instant message delivery, typing indicators, and live status updates.

PingBack's real-time layer is built on [Socket.IO](https://socket.io) with a Redis backplane. All live features — new messages, typing indicators, delivery receipts, and agent status — flow through this connection.

<Note>
  Socket.IO supports both WebSocket and long-polling transports. PingBack uses WebSocket by default and falls back to polling automatically when WebSocket is unavailable.
</Note>

## 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`.

```javascript theme={null}
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.

| Room                             | Purpose                                    |
| -------------------------------- | ------------------------------------------ |
| `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`:

```javascript theme={null}
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:**

| Field             | Type   | Description                                 |
| ----------------- | ------ | ------------------------------------------- |
| `id`              | number | Message ID.                                 |
| `content`         | string | Message text (or file URL for attachments). |
| `sender_type`     | string | `"customer"` or `"agent"`.                  |
| `conversation_id` | number | The conversation this message belongs to.   |
| `created_at`      | string | ISO 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:**

| Field             | Type   | Required | Description                                                  |
| ----------------- | ------ | -------- | ------------------------------------------------------------ |
| `content`         | string | Yes      | The message text.                                            |
| `conversation_id` | number | No       | Include to continue an existing conversation.                |
| `customer_data`   | object | Yes      | `{ 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.

```javascript theme={null}
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}`);
});
```
