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

# Headless chat SDK

> Use the Osvi AI chat session and interaction client with your own UI

The headless entry has no UI dependency and is safe to import on a server. Constructing a client opens no connection. Calling `start()` or sending the first message can initiate network requests and a connection.

```ts theme={null}
import { createChatClient } from "@osvi-ai/chat";

const chat = createChatClient({
  agentId: "agent_yourAgentId",
  baseUrl: "https://api.osvi.ai",
  auth: { mode: "anonymous" }
});

await chat.start();
const unsubscribe = chat.subscribe((state) => render(state));
await chat.send("Do you have rooms on Friday?");

// On teardown:
unsubscribe();
chat.destroy();
```

## Client options

`ChatClientOptions` accepts required `agentId`, optional `baseUrl` (default `https://api.osvi.ai`), and optional `auth` (anonymous by default). It also accepts `fetch`, `WebSocketImpl`, `store`, `page`, and `random` hooks for custom environments and controlled integrations. Server mode accepts a `getToken` callback from your backend; see [Logged-in users](/website-chat/server-mode).

## State

Subscribers receive a `ChatState` snapshot. Its fields include connection `status` (`idle`, `connecting`, `open`, `recovering`, `offline`, or `closed`), conversation `mode` (`ai` or `human`), `awaitingReply`, transcript `items`, `activeInteraction`, `interactionPending`, `agent`, and `error`. The agent value is null until anonymous bootstrap succeeds, or, in server mode, until the session opens; it is then set from the session snapshot.

Use `getState()` for a synchronous current snapshot. `subscribe(listener)` returns an unsubscribe function. A state item is a message, an interaction, a divider, or a `welcome` item (the agent's welcome message).

## Methods and outcomes

| Method | Purpose |
| - | - |
| `start()` | Bootstrap anonymous mode; server mode obtains a token and session from `getToken()`. |
| `send(text)` | Send a visitor message. |
| `respond(interactionId, response)` | Answer a pending interaction with a selection, text, date, or date range; resolves to `boolean`. |
| `retry(messageId)` | Retry a failed message using its existing idempotency identity; resolves to `boolean`. |
| `newSession({ keepHistory? })` | End the current conversation and begin a new one; resolves to `boolean`. `keepHistory` defaults to `true`; pass `false` to clear the transcript. |
| `getState()` | Read the current state snapshot. |
| `subscribe(listener)` | Observe state changes; returns an unsubscribe function. |
| `destroy()` | Close the socket, clear in-memory client state, and remove listeners. |

`send()` resolves with `{ ok: true, messageId }` when the client has queued/transmitted the message locally, or `{ ok: false, reason }` for `empty`, `destroyed`, `awaiting_interaction`, or `unavailable`. `ok: true` is not confirmation of server delivery. Watch the transcript item status: `sending` is local, and `sent` reflects server confirmation. The client retries or reconciles transport-level busy/unknown outcomes; a failed transcript item can be retried with its existing idempotency key.

## Errors

`state.error` holds the current error, with a stable `code`, a `message`, a `retryable` flag and, for an origin rejection, the rejected `origin`. Every code, with what it means and what to do, is in [Error codes](/website-chat/error-codes).


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