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

# RTM API Reference (V1)

RTM API (Real Time Messaging API) is the principal service to listen what is happening inside an specific tenant of Talqui. Events are sent on the RTM Events API WebSocket channel that you can open alongside your REST API channel. Events are ephemeral, that way you need to garantee to listen all events as soon that occurrs, if you need to react or create any action inside yout tenant you should use REST API together.

## Service

### Introduction

You may subscribe to events by opening a [Socket.IO](https://socket.io/) connection to the WebSocket endpoint.

**The RTM API endpoint URL is:** `wss://message-socket.talqui.chat`

**The Socket.IO path is:** `/socket/`

<Info>
  ⚠️ `/socket/` is the Socket.IO **path** option, it is not part of the connection URL. If you pass `wss://message-socket.talqui.chat/socket` as the URL, the client reads `/socket` as a **namespace** and keeps requesting the default path (`/socket.io/`), so the handshake never reaches the RTM API. Always keep only the host in the URL and declare the path in the client options.
</Info>

<Note>
  **There is a limit on the maximum number of connections that can be simultaneously open** with the RTM API (per-token, per-team and per-IP). This limit is quite high and can be revised at any time. Please make sure to teardown any unused connection before opening a new one. *Most use cases require a single RTM API connection.*
</Note>

***

### Authentication

The RTM API is authenticated during the Socket.IO handshake, through the `auth` object of the client options. Custom headers are not an option here — browsers do not allow headers to be set on a WebSocket handshake — so credentials always travel inside `auth`, and **both fields below are always required**:

| Field | Required | Description |
| - | - | - |
| `Authorization` | Yes | The same credential you would send in the `Authorization` header of the REST API. Supported formats and how to obtain them are described in the [Authentication guide](https://docs.talqui.chat/guides/introduction/authentication/). The credential must be scoped to the RTM API. |
| `tenantID` | Yes | Tenant whose events you want to receive. |

The RTM API accepts the two plugin credential formats:

```
Authorization: Plugin base64(pluginID:pluginToken)
Authorization: PluginConnection base64(pluginConnectionID:pluginConnectionToken)
```

```javascript theme={null}
import { io } from "socket.io-client";

const socket = io("wss://message-socket.talqui.chat", {
  path: "/socket/",
  transports: ["websocket"],
  auth: {
    Authorization: "Plugin <base64(pluginID:pluginToken)>",
    tenantID: "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  },
});

socket.on("connect_error", (error) => {
  console.error("RTM connection failed:", error.message);
});
```

<Note>
  📣 An `Authorization` that is invalid, expired or not scoped to the RTM API does not necessarily produce a `connect_error`. The transport may stay open while the connection remains unauthorized, and **no event is ever delivered**. If you connect successfully but never receive anything, review your `auth` object first.
</Note>

#### Listening to more than one tenant

A plugin is usually installed on many tenants, and a single connection can follow all of them. Beyond the `tenantID` sent in the handshake, you subscribe and unsubscribe tenants at any time by emitting the events below — that is how you follow every tenant that installed your plugin, and drop the ones that uninstalled it.

```javascript theme={null}
// Start receiving events from these tenants
socket.emit("plugin:connect:tenants", {
  tenantIDs: ["489e22f9-0a3a-4ac1-ab97-b7140cf61864"],
  pluginURN: "urn:talqui:plugin:your-plugin-name",
});

// Stop receiving events from these tenants
socket.emit("plugin:disconnect:tenants", {
  tenantIDs: ["489e22f9-0a3a-4ac1-ab97-b7140cf61864"],
  pluginURN: "urn:talqui:plugin:your-plugin-name",
});
```

<Info>
  📣 Subscriptions live only for the duration of the connection. Emit `plugin:connect:tenants` again on every `connect` event, otherwise a reconnection will leave you with an authenticated socket that receives nothing.
</Info>

***

## Base Objects

### Session

#### Session Base Object

* **Identifier:** `object:session:base`
* **Description:** Base version of session object

```json theme={null}
{
  "sessionID": "d6814578-560a-4b4b-95b8-085d465aa032",
  "contactID": "5527999999999",
  "createdAt": "2023-01-05T21:19:48.317Z",
  "operatorID": "52062885-83a7-465e-887b-3af324acebfa",
  "sessionActive": true,
  "sessionChannel": "whatsapp",
  "sessionLastMessageID": "73b8998b-b022-4a32-96a2-b1e1d927a4dc",
  "sessionMeta": {},
  "sessionRating": {
    "comment": null,
    "stars": 0
  },
  "sessionStatus": 0,
  "sessionTags": [],
  "sessionType": "manual",
  "tenantID": "db0180a1-40f4-4e03-a45f-0b7bfa6ddc9f",
  "updatedAt": "2023-01-15T03:33:38.338Z"
}
```

#### Session Extended Object

* **Identifier:** `object:session:extended`
* **Description:** Generally used over RTM API, it's an version extended of session with some id-fields already populated

```json theme={null}
{
  "sessionID": "d6814578-560a-4b4b-95b8-085d465aa032",
  "contactID": "5527999999999",
  "createdAt": "2023-01-05T21:19:48.317Z",
  "operatorID": "52062885-83a7-465e-887b-3af324acebfa",
  "sessionActive": true,
  "sessionChannel": "whatsapp",
  "sessionLastMessageID": "73b8998b-b022-4a32-96a2-b1e1d927a4dc",
  "sessionMeta": {},
  "sessionRating": {
    "comment": null,
    "stars": 0
  },
  "sessionStatus": 0,
  "sessionTags": [],
  "sessionType": "manual",
  "tenantID": "db0180a1-40f4-4e03-a45f-0b7bfa6ddc9f",
  "updatedAt": "2023-01-15T03:33:38.338Z",
  "contact": {
    "contactID": "5527999999999",
    "contactFirstname": "Cliente Acme",
    "contactLastname": "",
    "contactPhoto": null
  },
  "lastMessage": {
    "messageDirection": "inbound",
    "messageKey": "text",
    "messageValue": "Gostaria de renovar a assinatura com pagamento recorrente, é possível?",
    "messageStatus": 3,
    "messageID": "73b8998b-b022-4a32-96a2-b1e1d927a4dc"
  }
}
```

## Events

This events below represents messages that you will receive when connected to RTM API over websocket, those messages should be listen one by one and does not have acknolodge in delivery, só it's an notification event broker

### Session Events

Events that ocurrs under namespace of sessions, sessions represents an conversation between contact with a tenant, those sessions are rep

#### Session Change Type

* **Event**: `session:set:change_type`
* **Description:** When session change his type between `auto`, `queued` or `manual`

###### What represents each session type:

* `auto`: Session has this state when conversation is occurring under autonomous services, like chatbot, llms or anything similar.
* `queued`: This state only ocurrs when session is waiting to be handled by human, it's an transitory state but can be the first state when you dont have participation of chatbots in flow.
* `manual`: Type when a session is assigned to a human, no one autonomous messages can be sent in this state.

<Info>
  📣 Session types **queued** and **manual** will always occur, but if you don't have any chatbot installed in a tenant where the event occurs, the type **auto** will be skipped. This means that the initial state of a session will be **queued**, indicating that the session created is waiting for human treatment since its creation.
</Info>

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
  "type": "queued"
}
```

#### Session Set Routing

* **Event**: `session:set:routing`
* **Description:** Session was routed to an operator

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
}
```

#### Session Set Opened

* **Event**: `session:set:opened`
* **Description:** session was opened by some operator

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
}
```

#### Session Set Closed

* **Event**: `session:set:closed`
* **Description:** session was closed

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
}
```

#### Session Tag Added

* **Event**: `session:tag:added`
* **Description:** Session received a new tag

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
  "tag": "example"
}
```

#### Session Tag Removed

* **Event**: `session:tag:removed`
* **Description:** Session has an tag removed

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
  "tag": "example"
}
```

#### Session Rating Updated

* **Event**: `session:rating:updated`
* **Description:** Ocurrs when a session is rated by contact

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
  "stars": 5,
  "comment": "Nice treatment",
}
```

#### Session Request Initiated

* **Event**: `session:request:initiated`
* **Description:** Triggered when an a session is started by tenant with some contact

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
}
```

#### Session Summary Processed

* **Event**: `session:summary:processed`
* **Description:** Triggered when an session is summarized, event holds the session object and summarization of what was said in that session

<Info>
  📣 **This depends of some conditions**: Until today session must have more than 5 messages to be summarized. Other filters can be applied on that event avoiding to be triggered for each session. You can perform our own post-session async operations listening to event `session:set:closed`
</Info>

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
}
```

#### Session Metadata Updated

* **Event**: `session:meta:updated`
* **Description:** This event is fired when some metadata of session was changed.

<Note>
  📣 Very usefull to design **reactions at plugin widget**, you can listen that event on backend and then trigger reactions to widget instantly, like show some information or change pages.
</Note>

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "session": {
    <object:session:base>
  },
  "metaKey": "external_application_id",
  "metaValue": "12345",
}
```

***

### Contact Events

#### Contact attributes updated

* **Event**: `contact:attributes:update`
* **Description:** Contact attributes was updated

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "contact": "4ea57339-547c-4c16-a00a-9d60f0e287c4",
  "contact": {
    <object:contact:base>
  },
}
```

***

### Message Events

#### Message Received

* **Event**: `message:inbound`
* **Description:** Fired when a message is received at tenant

```json theme={null}
{
  "tenantID": "489e22f9-0a3a-4ac1-ab97-b7140cf61864",
  "sessionID": "7dea44ae-8f18-4991-826b-ce3b40d759d3",
  "operatorID": "72e80301-47ae-4e62-8be6-3340029ca5cb",
  "message": {
    <object:session:base>
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.