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

# Web Chat Without Voice

> Embed a text-only chat widget for a Telnyx AI Assistant on any website — no microphone, no WebRTC call, no voice minutes — or build a custom chat UI on the Assistant Chat API.

Give a website a text chat powered by the same AI Assistant that handles calls. The embeddable widget's `text-only` mode runs the conversation over WebSocket: no microphone permission prompt, no audio, no WebRTC session, and no voice minutes — visitors type, the assistant replies in text. For a fully custom chat interface, the Assistant Chat API sends a message to an assistant from your backend and returns the reply.

<Check>assistant created in [Mission Control](https://portal.telnyx.com/#/ai/assistants)</Check>

## Why text-only

Because no call is placed, a `text-only` chat session never bills voice minutes or speech: there is no per-minute Voice AI session charge for the chat. The assistant's replies still run LLM inference, billed as AI inference usage. Use this mode when visitors should type rather than talk.

## Embed the chat widget

The `<telnyx-ai-agent>` web component ships on npm as `@telnyx/ai-agent-widget`. In text-only mode the only required attribute is the assistant id:

```html theme={null}
<telnyx-ai-agent agent-id="assistant-xxx" text-only></telnyx-ai-agent>
<script async src="https://unpkg.com/@telnyx/ai-agent-widget"></script>
```

Install as a package with `npm install @telnyx/ai-agent-widget` and import the component where the app registers custom elements.

The widget opens directly into the transcript panel: there is no "Start Call" button and no collapsed pill state. Typed turns go to the assistant over a WebSocket; the reply streams back as text and renders in the transcript UI. The browser never holds a Telnyx API key — the connection is brokered server-side, the same anonymous trust the voice widget uses, so the only thing the page carries is the assistant id.

### Enable the assistant for web visitors

The assistant must allow anonymous web visitors:

* In [Mission Control](https://portal.telnyx.com/#/ai/assistants), open the assistant and, under **Telephony settings**, enable **Supports unauthenticated web calls** (`telephony_settings.supports_unauthenticated_web_calls`). This is the same opt-in the voice widget requires, and it is what marks an assistant as reachable from a public web page.
* No phone number is needed. The chat works for an assistant that has never been attached to a number.

### What fires and what bills

* DOM events work the same as on the voice widget: `agent.connected` (its detail carries the `conversationId`), `agent.disconnected`, `agent.error`, and the transcript events. Listen for transcript updates with `transcript.updated`, whose `detail` is the complete current transcript — replace the displayed transcript with it rather than appending.
* A session lives as a `web_chat` conversation keyed by `conversation_id`, alongside — never inside — any phone conversation for the same assistant. See [conversation keying](/docs/inference/ai-assistants/conversation-keying).

### Resuming a conversation

Pass the server-issued conversation id to keep one visitor in one conversation across page loads:

```html theme={null}
<telnyx-ai-agent agent-id="assistant-xxx" text-only conversation-id="my-conversation-123"></telnyx-ai-agent>
```

The visitor's **Start chat** control then resumes that conversation's server-side context with an empty local transcript.

## Build a custom chat UI

Embedding a prebuilt widget is optional. The Assistant Chat API drives any chat frontend through your own backend, which keeps the Telnyx API key server-side:

| Step | Call |
| - | - |
| Create a conversation | [Create a conversation](/api-reference/conversations/create-a-conversation) |
| Send the visitor's message | [Assistant Chat](/api-reference/assistants/assistant-chat) |
| Read back history | [Get conversation messages](/api-reference/conversations/get-conversation-messages) |

Assistant Chat records each turn against the `conversation_id`, so the history persists itself — there is no separate persist step. [Create Message](/api-reference/conversations/create-message) is only for inserting messages that did not go through the chat endpoint, such as importing an existing transcript.

Send a message with `content` and the conversation id:

```
POST /v2/ai/assistants/{assistant_id}/chat
```

```json theme={null}
{
  "content": "Do you ship to Canada?",
  "conversation_id": "42b20469-1215-4a9a-8964-c36f66b406f4"
}
```

`conversation_id` maintains context across requests; the response's `content` field is the assistant's reply. Set `stream: true` to receive the reply as Server-Sent Events — `delta` events carry content fragments while generated, and a final `done` event carries the full text.

A minimal backend flow: create a conversation once per visitor, then relay each typed turn.

<CodeGroup>
  ```bash Create the conversation once per visitor theme={null}
  curl -X POST https://api.telnyx.com/v2/ai/conversations \
    -H "Authorization: Bearer $TELNYX_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "name": "website-chat" }'
  # Store the returned conversation id in the visitor's session.
  ```

  ```bash Relay each typed turn theme={null}
  curl -X POST https://api.telnyx.com/v2/ai/assistants/$ASSISTANT_ID/chat \
    -H "Authorization: Bearer $TELNYX_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "content": "Do you ship to Canada?",
      "conversation_id": "42b20469-1215-4a9a-8964-c36f66b406f4"
    }'
  # Return the response's `content` field to the browser as the reply.
  ```
</CodeGroup>

Forward the assistant's `content` to your frontend, store the `conversation_id` in the visitor's session, and pass it back on every subsequent turn. Because your server brokers every request, the API key never reaches the browser.

## Assistant behavior in chat

Instructions, model, knowledge bases, and insights configured on the assistant apply to chat the same as to calls. Server-side tools run as usual. Three things differ:

* The conversation runs as its own `web_chat` channel; instructions referencing `{{telnyx_conversation_channel}}` see `web_chat`.
* Voice-specific telephony settings — phone number, voice, transcription — are simply unused; there is no audio path in a text-only chat.
* Client-side tools are unavailable in a text-only widget: the chat path is request/response, so a browser tool announced on this path could never run. An assistant that relies on client-side tools is not a fit for `text-only` — server-side tools are the ones that run in chat.
