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

# Session Management

> How a session is born, who owns it at each moment, how it ends, and how a plugin shows the typing indicator while it prepares a reply.

## Overview

Every conversation in Talqui is a [Session](/guides/platform/sessions). Along its life a session moves between owners: an automation (a chatbot or an AI agent), the queue of human operators, one specific operator, and finally the history of closed conversations. Knowing these states tells your integration what is happening in a conversation and what it is allowed to do there.

Two fields describe the state:

* `sessionActive`: `true` while the conversation is open, `false` once it is closed.
* `sessionType`: who owns an open conversation.

| `sessionType` | Owner | What it means |
| - | - | - |
| `auto` | Automation | A chatbot or AI agent installed in the tenant answers the contact. |
| `queued` | The queue | The conversation waits for a human operator. It shows in the **Queue** view of the Talqui app. |
| `manual` | One operator | An operator took the conversation (`operatorID` is set). Automations stop answering. |

Other fields record the timeline: `queuedAt` (first time it entered the queue), `manualAt` (first time an operator took it), `closedAt` and `closeMotive` (when and why it ended).

## How a session is born

A session starts in one of two ways: the contact writes to the tenant, or the tenant opens the conversation (an operator, a campaign, or your backend through [Session Start](/guides/platform/sessions/session-start)).

**When the contact writes**, the first type depends on whether the tenant has an automation installed. Talqui looks for an enabled connection of a chatbot plugin (the Talqui chatbot, AI agents, or a third-party chatbot plugin):

* **With an automation**, the session starts as `auto` and the automation receives the message.
* **Without one**, the session starts as `queued` and waits for an operator.

**When the tenant opens the conversation** through Session Start, the request chooses the type with `sessionType`, and Talqui falls back to the queue when the choice cannot be honored:

* `auto` without an automation installed becomes `queued`.
* `manual` without an `operatorID` becomes `queued`.

<Note>
  A session that enters the queue may leave it right away. When the tenant has distribution rules turned on, Talqui picks an operator as soon as the session is queued, and it becomes `manual` in the same step.
</Note>

## Session states

A session goes through two layers of state. The first is its lifecycle: it is open, then closed, and may wait for a rating on the way out.

```mermaid theme={null}
stateDiagram-v2
    direction LR
    state "Open" as open
    state "Closed" as closed
    state "Waiting for rating" as rating

    [*] --> open: created
    open --> closed: closed
    closed --> open: reopen window
    closed --> rating: rating requested
    rating --> [*]: rated or expired
    closed --> [*]
```

### Moving between owners

While the session is open, `sessionType` tells who owns it, and ownership moves as the conversation progresses.

```mermaid theme={null}
stateDiagram-v2
    direction LR
    [*] --> auto: automation installed
    [*] --> queued: no automation
    [*] --> manual: opened with an operator
    auto --> queued: handover
    queued --> manual: operator takes it
    manual --> queued: operator removed
    queued --> auto: back to automation
    manual --> auto: back to automation
```

| From | To | What causes it |
| - | - | - |
| `auto` | `queued` | The automation transfers the conversation to the human team, or the tenant forces new conversations to the queue. |
| `queued` | `manual` | An operator picks the conversation, replies to it (when *assign on reply* is on), or a distribution rule assigns it. |
| `manual` | `queued` | The operator is removed from the conversation, for example when it moves to an inbox the operator has no access to. |
| any | `auto` | The conversation is given back to the automation. |

A request to move a conversation to the queue only applies when it is `auto`. A conversation that an operator already owns is never pulled back to the queue by that request.

The type can also be changed through the API with `PATCH /tenants/:tenantID/sessions/:sessionID/type` and a body `{ "sessionType": "auto" | "queued" | "manual" }`.

### Closing

A closed session has `sessionActive: false`, `closedAt` set, its owner cleared (`operatorID: null`) and `sessionType` reset to `auto`. The `closeMotive` field tells why it ended. Common values:

| `closeMotive` | Meaning |
| - | - |
| `OPERATOR` | An operator ended the conversation. A motive the operator picked from the tenant's list replaces it. |
| `INACTIVITY` | The contact did not write for longer than the tenant's inactivity timeout (4 hours by default). Talqui checks idle sessions every 5 minutes. |
| `EOS_CHATBOT` | The automation ended the conversation. |
| `EOS_RATING` | The conversation ended with the contact's rating. |
| `SESSION_HANDOFF` | The conversation moved to another channel. |

After a session is closed, the next message from the contact opens a **new** session, with two exceptions:

* **Waiting for a rating.** When the conversation is closed asking for a satisfaction rating (CSAT), it stays closed but waits for the answer. While the tenant's rating window is open, the contact's next message is read as the rating and belongs to the closed session. The cycle ends when the contact answers or the window expires.
* **Reopen window.** A tenant can turn on a short reopen window (15 minutes by default, off for new tenants). A contact who writes again inside it, typically a "thanks!" right after the operator closed, reopens the same session: back to the same operator (`manual`) when an operator was talking to them, otherwise `auto` or `queued` as for a new conversation.

## Typing indicator

A plugin that takes a while to answer, such as an AI agent calling a model or an integration looking up an order, can show the contact that a reply is on its way. Talqui shows the indicator in the conversation inside the Talqui app and, where the channel supports it, to the contact.

```bash theme={null}
POST https://services-api.talqui.chat/v1/tenants/{tenantID}/sessions/{sessionID}/typing
```

Full reference: [Publish session typing](/api-reference/services-api/sessions/publish-session-typing).

### When to call it

Call `start` as soon as your plugin receives the contact's message, then send the reply as usual. There is no need to call `stop` after replying: the indicator ends when the reply arrives.

```mermaid theme={null}
sequenceDiagram
    participant C as Contact
    participant T as Talqui
    participant P as Your plugin

    C->>T: message
    T->>P: message delivered to the plugin
    P->>T: POST .../typing { "action": "start" }
    T-->>C: "typing..."
    Note over P: prepares the reply
    P->>T: send the reply
    T-->>C: reply (the indicator ends)
```

### Authentication

The endpoint accepts machine credentials only. See the [Authentication guide](/guides/introduction/authentication) for how to build each header.

* `PluginConnection`: the connection of your plugin in that tenant.
* `Plugin`: your plugin's own credential, accepted only when the plugin is installed in that tenant.

Operator tokens are refused with `403`. The indicator is published on behalf of an automation, never of a person.

### Request

| Field | Type | Required | Description |
| - | - | - | - |
| `action` | `"start"` \| `"stop"` | yes | `start` shows the indicator, `stop` clears it on the channels that support it. |
| `messageID` | uuid | no | The contact message being answered. Omit it (recommended). |

```bash theme={null}
curl --request POST \
  --url https://services-api.talqui.chat/v1/tenants/<TENANT_ID>/sessions/<SESSION_ID>/typing \
  --header 'Authorization: PluginConnection <BASE64(pluginConnectionID:pluginConnectionToken)>' \
  --header 'content-type: application/json' \
  --data '{ "action": "start" }'
```

```ts theme={null}
const credentials = Buffer.from(`${pluginConnectionID}:${pluginConnectionToken}`).toString('base64');

await fetch(`https://services-api.talqui.chat/v1/tenants/${tenantID}/sessions/${sessionID}/typing`, {
  method: 'POST',
  headers: {
    Authorization: `PluginConnection ${credentials}`,
    'content-type': 'application/json',
  },
  body: JSON.stringify({ action: 'start' }),
});
```

### The reference message

The indicator is always attached to **the latest message the contact sent in the session**. When you omit `messageID`, Talqui finds that message for you, and this is the recommended way to call the endpoint.

When you send `messageID`, it must be exactly that message. Otherwise the call is refused:

* a message of another session answers `404 TypingMessageNotFoundError`;
* a message sent by the tenant answers `409 TypingMessageNotInboundError`;
* an older contact message answers `409 TypingMessageNotLatestError`, with the latest message in `fields[0].allowed` so you can retry.

<Warning>
  On WhatsApp the typing indicator also **marks the contact's message as read**, together with every message before it. Anchoring it to the right message is what keeps the contact from seeing "read" on a message nobody is answering.
</Warning>

### Response

The endpoint answers `202 Accepted`: the indicator reaches the channel asynchronously.

```json theme={null}
{
  "published": true,
  "action": "start",
  "messageID": "989cd1ce-2ab4-4e05-baf0-68382e81c7d7",
  "hasExternalID": true
}
```

* `messageID`: the contact message the indicator was attached to.
* `hasExternalID`: `false` when that message has no identifier on the channel. Only the Talqui app shows the indicator then.
* `published: false` with `reason: "throttled"`: see below.

### Throttling

Talqui publishes one `start` per session every 5 seconds. Extra calls inside that window answer `202` with `"published": false, "reason": "throttled"`; they are not errors and need no retry. A `stop` frees the window, so the next `start` goes out right away.

### Behaviour by channel

| Where | What the contact or operator sees | When it ends | Effect of `stop` |
| - | - | - | - |
| Talqui app | "Typing" on the conversation | On the next message, or after 90 seconds | None |
| WhatsApp (official API) | "typing…" under the contact name, and the message is marked as read | When the reply arrives, or after about 25 seconds | None |
| WebChat | Typing indicator in the widget | When the reply arrives | Clears it |
| Other channels | Nothing on the channel; only the Talqui app shows it | — | — |

### Errors

Every status and error code of the endpoint is listed in the [API reference](/api-reference/services-api/sessions/publish-session-typing). The indicator is cosmetic: if a call fails, carry on and send the reply.

### References

* [Sessions](/guides/platform/sessions)
* [Session Start](/guides/platform/sessions/session-start)
* [Publish session typing](/api-reference/services-api/sessions/publish-session-typing)
* [Authentication guide](/guides/introduction/authentication)


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