> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://murf.ai/api/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://murf.ai/api/docs/_mcp/server.

Murf’s WebSocket implementation is based on the concept of a **Context ID** — a unique identifier used to track a specific TTS request. Context ID ensures continuity in the conversation, especially when the input text is generated in real time (e.g., via an LLM), comes in parts, or when the interaction is interrupted. It serves as a proxy for a single turn in the interaction between a user and the agent.

## Why Use a Context ID?

* **Maintains Conversational Flow:** Links input and output across split or partial messages.
* **Handles Interruptions Gracefully:** If a user interrupts the agent, the Context ID ensures that the current request can be cancelled or skipped.
* **Supports Multi-Turn Interactions:** Essential for structured flows like bookings, troubleshooting, or guided forms.
* **Simplifies Handoff and Debugging:** If support is needed, the Context ID allows you to trace exactly what happened in a specific interaction turn.

![Simple WebSocket Connection](/api/docs/_fern-img/b121ce4ffdbd15aefccc85bc2529206c6d0864259923bec773bd3b360e626ee2.webp)

![Simple WebSocket Connection](/api/docs/_fern-img/77597f5f1a75eea7e1caf6c1cd7f9f39f5741cd2eee442587207c674449c03ea.webp)

## Working with Context IDs

#### Input Stream

* Assign a new `context_id` for each turn in the conversation.
* The `end` parameter should be set to `true` at the end of each turn. This clears the context and allows the next turn to start.
* Ensure input text includes proper punctuation for better prosody and consistent audio output.

> **Note**
>
> If you omit `context_id`, the server uses a per-connection identifier but
> echoes `null` back to you. A single-stream client may omit it, but must not
> key its state on the echoed value.

### Voice settings and Context IDs

A `context_id` does not change the values in `voice_config`. It scopes the
configuration to one independent context:

* A `voice_config` with a `context_id` applies only to text sent with that same
  `context_id`.
* A `voice_config` without a `context_id` applies only to the default context
  (text that also omits `context_id`).
* Named contexts do not inherit the default context's voice settings or the
  settings of another named context.
* Once configured, a context keeps its settings for its lifetime, even if the
  default context is configured differently later.

When using named contexts, initialize each one by sending `voice_config` and
the same `context_id` before its first text frame. If text reaches a context
without its own configuration, Murf uses the default voice and sends a
`NO_VOICE_CONFIG` warning. A configuration without `voiceId` similarly falls
back and sends `NO_VOICE_ID`. See
[Errors & Warnings](/api/docs/text-to-speech/errors).

> **Note**
>
> For a single default stream, omitting `context_id` from both the
> configuration and text frames is valid. Do not mix an unscoped
> configuration with text that has a named `context_id`.

#### Output Audio

* The response will include the same `context_id`, allowing you to match responses with their corresponding inputs.
* A `final` flag will indicate that all audio for that context has been sent.
* Output is streamed in the same order that input text was received.

#### Concurrency

Each simultaneously active `context_id` counts toward your streaming concurrency limit. Closing a turn with `{"end": true}` frees its slot. If you exceed the limit you receive an `ACTIVE_CONTEXT_LIMIT_EXCEEDED` error. See [Rate Limits](/api/docs/resources/rate-limits) and [Errors & Warnings](/api/docs/text-to-speech/errors).

#### Handling Interruptions

* If the user interrupts the agent mid-response, start a new `context_id` for the next turn.
* Murf’s WebSocket supports multiplexing, so multiple `context_id`s can run independently over the same connection.
* To cancel a pending or in-progress turn, use the `clear` parameter. If synthesis hasn’t started, the request is cancelled. If synthesis has started, the audio will still play to completion.

#### `clear` semantics

* `{"clear": true}` discards the context and any pending audio. This is what you use for barge-in. If you are using word timestamps, also drop every timestamp whose `start_s` is past the current playback position.
* `{"clear": false}` means "do not clear" and is safely ignored, so it is fine to send a fully-populated payload with the key present.
* `text` sent in the **same frame** as `clear` is dropped, and you receive a `TEXT_IGNORED_WITH_CLEAR` warning. Send the clear and the new text as two separate frames.

## Example for using Context ID in a Voice Agent

Let’s say you’re building a voice agent that helps users book flights.

#### Establish WebSocket Connection

You open a WebSocket connection when the conversation starts. This connection stays open and allows real-time audio streaming between user and agent.

#### Use a Context ID for Each Agent Response (Turn)

#### Turn 1

**User says**: “I want to book a flight to Paris.”

Your backend processes this and generates an agent response:

**Agent text**: “Sure, when would you like to travel?”

First configure `turn_1`, then send text with the same `context_id`. Each
JSON object is a separate WebSocket frame:

```json
{
  "voice_config": {
    "voiceId": "en-US-gordon",
    "locale": "en-US",
    "style": "Conversation"
  },
  "context_id": "turn_1"
}
```

```json
{
  "context_id": "turn_1",
  "text": "Sure, when would you like to travel?",
  "end": true
}
```

Murf returns audio with context\_id: "turn\_1" so you can play it back to the user.

#### Turn 2

**User says**: “Next Friday.”

**Agent response**: “Got it. Do you prefer morning or evening flights?”

Because `turn_2` is a new context, configure it separately. It does not
inherit the voice settings from `turn_1`:

```json
{
  "voice_config": {
    "voiceId": "en-US-gordon",
    "locale": "en-US",
    "style": "Conversation"
  },
  "context_id": "turn_2"
}
```

```json
{
  "context_id": "turn_2",
  "text": "Got it. Do you prefer morning or evening flights?",
  "end": true
}
```

Murf returns audio tagged with context\_id: "turn\_2".

#### Handle Interruptions

If the agent is mid-response and the user interrupts (e.g., says “Wait, make that Saturday”):

* Stop playback of the current audio. The `clear: true` flag cancels any pending or incomplete responses tied to earlier contexts.
* Clear the previous context:

```json
{
  "context_id": "turn_2",
  "clear": true
}
```

* Configure the new context:

```json
{
  "voice_config": {
    "voiceId": "en-US-gordon",
    "locale": "en-US",
    "style": "Conversation"
  },
  "context_id": "turn_3"
}
```

* Send the updated agent reply with the same new `context_id`:

```json
{
  "context_id": "turn_3",
  "text": "Saturday works. Do you want to fly direct or stopover?",
  "end": true
}
```

Murf returns audio tagged with context\_id: "turn\_3".

> **Warning**
>
> Send these as three separate frames. If you put `clear` and `text` in
> the same frame, the text is dropped and you receive a
> `TEXT_IGNORED_WITH_CLEAR` warning.

## Why This Matters

* Each context ID represents one agent turn in conversation.
* You maintain clean tracking of each response, even with interruptions.
* WebSocket handles all turns over a single connection, supporting real-time, fluid interaction.