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

# MeetStream — MIA API Reference

MIA (MeetStream Infrastructure Agent) configurations define how an AI agent behaves when deployed into a meeting. Use these endpoints to create, retrieve, update, and delete agent configurations programmatically — no dashboard required.

**Base URL:** `https://api.meetstream.ai`
**Authentication:** `Authorization: Token <YOUR_API_KEY>`
**Content-Type:** `application/json`

Applies to: **Google Meet, Zoom, Microsoft Teams**
Support: docs.meetstream.ai · API: api.meetstream.ai

> **Before you start:** Agent configurations require that you have configured the relevant provider API keys in MeetStream. Add keys via the MeetStream dashboard → Integrations page (or the Integrations API) before creating an agent that references those providers.

---

## Endpoints

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/v1/mia` | Create a new agent configuration |
| `GET` | `/api/v1/mia` | Retrieve one or all agent configurations |
| `PUT` | `/api/v1/mia` | Update an existing agent configuration |
| `DELETE` | `/api/v1/mia` | Delete an agent configuration |

---

## POST /api/v1/mia

Create a new agent configuration.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `agent_name` | `string` | Yes | Display name for this agent configuration |
| `mode` | `string` | Yes | `"pipeline"` or `"realtime"` — see [Operating Modes](/guides/mia/what-is-mia#operating-modes) |
| `model` | `object` | Yes | LLM or realtime model configuration (see below) |
| `voice` | `object` | Pipeline only | TTS voice configuration (see below) |
| `transcriber` | `object` | Pipeline only | STT transcription configuration (see below) |
| `agent` | `object` | No | Agent behavior: turn detection, VAD, interruptions, MCP servers, custom functions. Auto-filled with defaults if omitted (pipeline mode). |
| `audio` | `object` | No | Audio processing configuration. Defaults to `{ "sample_rate": 24000, "num_channels": 1 }` if omitted. |
| `wake_word` | `object` | No | Wake word gating — pipeline mode only. `words` is **required** when `enabled=true`. |
| `avatar` | `object` | No | Avatar configuration (Anam provider) |

### Nested: `model` (Pipeline Mode)

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `provider` | `string` | **Yes** | — | LLM provider: `"openai"`, `"anthropic"`, `"xai"`, or `"google"` |
| `model` | `string` | **Yes** | — | Model name — e.g. `"gpt-4.1"`, `"gpt-4.1-mini"`, `"grok-3"` |
| `system_prompt` | `string` | **Yes** | — | System prompt defining agent personality and behavior. Supports `{{variable}}` template placeholders — see [Template Variables](#template-variables). |
| `temperature` | `number` | No | `0.8` | LLM temperature (0–2) |
| `max_tokens` | `integer` | No | *(none — model default)* | Maximum response tokens |
| `first_message` | `string` | No | `""` | Pipeline greeting spoken when the bot joins. Supports `{{variable}}` placeholders. |
| `top_p` | `number` | No | *(provider default)* | Nucleus-sampling control where supported |
| `frequency_penalty` | `number` | No | *(provider default)* | Penalizes repeated token frequency where supported |
| `presence_penalty` | `number` | No | *(provider default)* | Penalizes already-used tokens where supported |

### Nested: `model` (Realtime Mode)

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `provider` | `string` | **Yes** | — | Realtime provider: `"openai"`, `"xai"`, or `"google"` |
| `model` | `string` | No | *per-provider* | Model name — auto-filled if omitted (see provider table below). xAI model is implicit (hardcoded server-side). |
| `system_prompt` | `string` | **Yes** | — | System prompt defining agent personality and behavior. Supports `{{variable}}` template placeholders — see [Template Variables](#template-variables). |
| `voice` | `string` | No | *per-provider* | Voice name — auto-filled if omitted (see provider table below) |
| `temperature` | `number` | No | `0.8` | Temperature (0–2) |
| `max_response_output_tokens` | `integer` | No | *(model default)* | Max output tokens — OpenAI only, must be positive |
| `thinking_config` | `object` | No | — | Google Gemini thinking: `{ "include_thoughts": bool, "thinking_budget": int }` |
| `modalities` | `array[string]` | No | `["text", "audio"]` | Realtime output modalities. Use `["text"]` for text-only output. |
| `top_p` | `number` | No | *(provider default)* | Nucleus-sampling control where supported |
| `enable_affective_dialog` | `boolean` | No | `false` | Google native-audio expressive responses |
| `proactivity` | `boolean` | No | `false` | Google native-audio model may choose not to respond to irrelevant input |
| `disable_automatic_activity_detection` | `boolean` | No | `false` | Disable Gemini's built-in VAD. Configure an external STT model when using this option. |

#### Realtime providers — model and voice values

| Provider | `model` | Default `model` | `voice` options | Default `voice` |
|----------|---------|-----------------|-----------------|-----------------|
| `openai` | `"gpt-realtime-mini"`, `"gpt-realtime-1.5"`, `"gpt-4o-realtime-preview"`, `"gpt-4o-mini-realtime-preview"` | `gpt-realtime-mini` | `alloy`, `ash`, `ballad`, `cedar`, `coral`, `echo`, `fable`, `marin`, `nova`, `onyx`, `sage`, `shimmer`, `verse` | `coral` |
| `xai` | *Not needed* (hardcoded internally) | — | `Ara`, `Eve`, `Leo`, `Rex`, `Sal` | `Ara` |
| `google` | `"gemini-2.5-flash-native-audio-preview-12-2025"` | `gemini-2.5-flash-native-audio-preview-12-2025` | `Puck`, `Charon`, `Kore`, `Fenrir`, `Aoede`, `Leda`, `Orus`, `Zephyr` | `Puck` |

### Nested: `voice` (Pipeline Mode)

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `provider` | `string` | **Yes** | — | TTS provider: `"openai"`, `"elevenlabs"`, or `"xai"` |
| `voice_id` | `string` | **Yes** | — | Voice identifier for the chosen provider (see table below) |
| `model` | `string` | No | *per-provider* | TTS model name — auto-filled based on provider if omitted (see table below) |
| `speed` | `number` | No | `1.0` | Playback speed multiplier (provider-dependent support) |

#### Voice model defaults by provider

If you omit `voice.model`, the API fills it automatically:

| Provider | Default `model` | Example `voice_id` values |
|----------|----------------|---------------------------|
| `openai` | `tts-1` | `alloy`, `ash`, `coral`, `echo`, `fable`, `nova`, `onyx`, `sage`, `shimmer`, `verse` |
| `elevenlabs` | `eleven_turbo_v2_5` | Your ElevenLabs voice ID (e.g. `cjVigY5qzO86Huf0OWal`) — browse at [elevenlabs.io](https://elevenlabs.io). Other models: `eleven_flash_v2_5`, `eleven_multilingual_v2` |
| `xai` | `tts-1` | `ara`, `eve`, `leo`, `rex` |

> **Important:** ElevenLabs voice IDs are provider-specific UUIDs — do not use OpenAI voice names like `"alloy"` with `provider: "elevenlabs"`. This will cause a 403 error from ElevenLabs.

### Nested: `transcriber` (Pipeline Mode)

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `provider` | `string` | **Yes** | — | STT provider: `"openai"`, `"deepgram"`, `"assemblyai"`, or `"xai"` |
| `model` | `string` | No | *per-provider* | STT model name — auto-filled based on provider if omitted (see table below) |
| `language` | `string` | No | `"en"` | Language code — e.g. `"en"`, `"es"` |
| `boostwords` | `array[string]` | No | `[]` | Words to boost recognition accuracy. Also accepted as `boost_words` (normalised automatically). Wake word phrases are auto-merged into this list. |

#### Transcriber model defaults by provider

If you omit `transcriber.model`, the API fills it automatically:

| Provider | Default `model` | Other valid models |
|----------|----------------|-------------------|
| `deepgram` | `nova-2` | `nova-3`, `nova-2-conversationalai`, `nova-2-phonecall`, `flux-general` |
| `openai` | `whisper-1` | — |
| `assemblyai` | `u3-rt-pro` | `universal-streaming`, `universal-streaming-multilingual` |
| `xai` | `stt-1` | — |

### Nested: `agent`

The `agent` block is optional. If omitted entirely on a pipeline-mode create, the API fills it with sensible defaults so you don't need to specify every field.

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `response_modality` | `string` | No | `"audio"` | `"audio"` for spoken output, `"chat"` for meeting-chat output, or `"action"` for silent tool execution. Legacy aliases such as `"voice"` are accepted. |
| `turn_detection` | `string` | No | `"vad"` | Turn-detection strategy: `"vad"`, `"stt"`, `"multilingual"`, or `"manual"` |
| `endpointing_mode` | `string` | No | `"fixed"` | `"fixed"` (constant delay) or `"dynamic"` (adapts to conversation rhythm) |
| `interruption_mode` | `string` | No | `"vad"` | `"vad"` (silence-based) or `"adaptive"` (LiveKit Cloud ML barge-in detection, pipeline mode) |
| `enable_interruptions` | `boolean` | No | `true` | Whether users can interrupt agent speech |
| `user_away_timeout` | `number` | No | `15` | Seconds of silence before the agent considers the user away |
| `preemptive_generation` | `boolean` | No | `false` | Start LLM generation before the user finishes speaking |
| `false_interruption_timeout` | `number` | No | `2.0` | Seconds to wait before confirming a false interruption |
| `resume_false_interruption` | `boolean` | No | `true` | Resume agent speech after a false interruption |
| `interruptions` | `object` | No | mode-specific | Interruption thresholds: `min_duration_seconds`, `word_threshold`, and optional `energy_threshold` |
| `vad_type` | `string` | No | `"server_vad"` | Realtime VAD strategy. OpenAI also supports `"semantic_vad"`. |
| `vad_eagerness` | `string` | No | `"medium"` | Semantic VAD eagerness: `"auto"`, `"low"`, `"medium"`, or `"high"` |
| `vad_deactivation_threshold` | `number` | No | *(model default)* | Optional pipeline VAD deactivation threshold |
| `min_endpointing_delay` | `number` | No | `0.5` | Minimum silence (seconds) before treating speech as complete |
| `max_endpointing_delay` | `number` | No | `3.0` | Maximum silence (seconds) before forcing endpointing |
| `vad_activation_threshold` | `number` | No | `0.5` | VAD sensitivity (0–1, higher = less sensitive) |
| `vad_min_silence_duration_ms` | `integer` | No | `550` | Milliseconds of silence needed to trigger endpointing |
| `vad_min_speech_duration_ms` | `integer` | No | `50` | Minimum speech duration (ms) to start processing |
| `vad_prefix_padding_duration_ms` | `integer` | No | `300` | Audio padding (ms) prepended to captured speech |
| `tools` | `array[string]` | No | `[]` | Built-in tool names to enable, currently `current_time` and `weather_now` |
| `mcp_servers` | `array[object]` or `object` | No | `[]` | MCP server configurations. Arrays and named-object maps are accepted. |
| `mcp_fail_open` | `boolean` | No | `true` | If MCP startup fails, retry the agent session without MCP tools |
| `custom_functions` | `array[object]` | No | `[]` | User-defined HTTP endpoints registered as agent tools — see [Custom Functions](#custom-functions). Max 20 per agent. |
| `tool_results_to_chat` | `boolean` | No | `false` | In audio mode, also send compact tool-result details to meeting chat |
| `speaker_aware_responses` | `boolean` | No | `false` | When `true`, every user utterance is prefixed with the active speaker's name (e.g. `[Rahul]: ...`) before reaching the LLM, so the agent can distinguish who is speaking on multi-participant calls. Pipeline mode only. See [Speaker-Aware Responses](#speaker-aware-responses). |
| `speaker_aware_prompt` | `string` | No | _MeetStream default_ | Optional instruction text appended to your `model.system_prompt` when `speaker_aware_responses=true`. Lets you customise how the LLM should interpret the bracketed `[Speaker Name]:` prefix (address people by name, summarise per-speaker at the end, ignore the names entirely, etc.). Max **2000 characters**. If omitted, MeetStream supplies a sensible default. Has no effect when `speaker_aware_responses=false`. See [Speaker-Aware Responses](#speaker-aware-responses). |

### Nested: `agent.mcp_servers[]`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `url` | `string` | Yes | Streamable HTTP MCP endpoint (must be HTTPS) |
| `headers` | `object` | No | Authentication headers — e.g. `{ "Authorization": "Bearer <token>" }`. Environment expansion requires the entire value to be `env:VAR_NAME`. |
| `allowed_tools` | `array[string]` | No | Whitelist of tool names. Omit to allow all tools from this server |
| `timeout` | `number` | No | Per-call timeout in seconds (default: 10) |

### Nested: `agent.custom_functions[]`

Each entry registers a single HTTPS endpoint as an LLM-callable tool. Authentication is handled by you — put a narrowly scoped bearer token or API key in `headers`. See the [Custom Functions Guide](/guides/mia/mia-custom-configurations) for end-to-end setup and response-variable examples.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Snake-case identifier matching `^[a-z][a-z0-9_]*$`, max 64 chars. Unique per agent. Must not collide with built-ins (`current_time`, `weather_now`) or reserved prefixes (`meetstream_`, `mia_`, `lk_`). |
| `description` | `string` | Yes | Short natural-language description. Shown to the LLM so it knows when to call the function. |
| `method` | `string` | No | HTTP method: `GET`, `POST`, `PATCH`, `PUT`, or `DELETE`. Defaults to `POST`. |
| `url` | `string` | Yes | Fully-qualified HTTPS URL. Hostname must resolve to a public IP (private/RFC-1918 targets are rejected for SSRF protection). |
| `headers` | `object` | No | Extra HTTP headers. `{{variable}}` placeholders are resolved from dynamic vars. Environment expansion requires the whole value to be `env:VAR_NAME` and a variable provisioned in the managed runtime. MeetStream always adds `X-Bot-ID` unless supplied; `X-Agent-ID` is optional and must not be required by your endpoint. |
| `query_params` | `object` | No | Flat key/value map appended as query string. |
| `parameters` | `object` | No | JSON Schema describing the arguments the LLM must supply. Must be `{"type": "object", "properties": {...}, "required": [...]}`. If omitted, the tool accepts no arguments. |
| `payload_args_only` | `boolean` | No | When `true`, the request body is the raw `args` object. When `false` (default), the body is `{"name", "bot", "args"}`. |
| `timeout_s` | `number` | No | Total request timeout in seconds. Range `1–120`, default `30`. |
| `retries` | `integer` | No | Number of retries on 5xx / network errors (exponential backoff). Range `0–5`, default `2`. |
| `response_cap_chars` | `integer` | No | Maximum characters of the response body passed back to the LLM. Range `1000–50000`, default `15000`. Longer responses are truncated with a trailing notice. |
| `speak_during_execution` | `boolean` | No | When `true`, the agent emits a filler utterance while the HTTP call is in flight. Default `false`. |
| `speak_during_prompt` | `string` | No | Filler text to speak during execution (e.g. `"Let me check that for you."`). Only used when `speak_during_execution=true`. Max 500 chars. If omitted, a default filler ("One moment please.") is used. |
| `speak_after_execution` | `boolean` | No | Default `true`. When `false`, the agent's turn ends silently after the tool completes — useful for pure side-effect calls (e.g. create-ticket, update-CRM). |
| `response_variables` | `array[object]` | No | Extract values from a successful JSON response into in-memory session variables. They resolve in later custom-function templates and stored-prompt rebuilds. Max 20 entries per function. |

By default, `POST`, `PUT`, and `PATCH` requests use the body `{"name", "bot", "args"}`. The `bot` object always contains `bot_id`; `agent_id` is optional. Its `dynamic_vars` contains values extracted from earlier custom-function responses, not the bot's initial `agent_config_params`. `GET` and `DELETE` send no body unless `payload_args_only=true`.

### Nested: `agent.custom_functions[].response_variables[]`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Variable name matching `^[a-zA-Z_][a-zA-Z0-9_]*$`, max 64 chars, unique within the function. |
| `path` | `string` | Yes | Dot-notation path into the JSON response — e.g. `"data.user.city"`. Brackets and `$.` prefixes are not allowed. Missing paths are skipped silently. |

### Nested: `wake_word` (Pipeline Mode Only)

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `enabled` | `boolean` | No | `true` at pipeline runtime | Whether wake word gating is active. Set explicitly to `false` for always-on listening. |
| `words` | `array[string]` or `string` | **Yes when explicitly creating an enabled block** | `["hey assistant", "hello bot"]` at runtime | Trigger phrases. Comma-separated string or array. An explicit `enabled=true` block returns 400 if `words` is empty or missing. |
| `timeout` | `number` | No | `30` | Seconds the agent stays active after the wake word is heard. Each new utterance during this window rolls the timer forward. |
| `bypass_below_participants` | `integer` | No | `0` (off) | Auto-disable the wake-word gate when the meeting has at most this many human participants. The bot is not counted — set to `1` for 1:1 calls (you + bot = bypass active). `0` keeps the gate on regardless of meeting size. Range: `0`–`50`. Reacts live to mid-call joins/leaves. |
| `max_listening_window` | `integer` | No | `0` (off) | Hard cap, in seconds, on a single listening session even if the user keeps talking. `0` disables the cap and preserves the rolling-extend behaviour. When set, the listening window cannot extend past `wake-word-detected-at + max_listening_window` — once it expires the user must say the wake word again. Range: `0`–`7200`. |

> **Runtime default:** A pipeline agent with no stored `wake_word` block starts with gating enabled, the phrases `["hey assistant", "hello bot"]`, and a 30-second timeout. Set `wake_word.enabled=false` explicitly when the agent should listen to every utterance.
>
> **Tip — picking values**: Leave both adaptive fields at `0` for shared meetings where the wake word is the privacy contract. Set `bypass_below_participants: 1` for direct 1:1 calls. Combine `max_listening_window: 600` with the default `timeout: 30` for a hard ten-minute listening ceiling.

### Speaker-Aware Responses

Pipeline mode only. When `agent.speaker_aware_responses: true`, every transcribed user utterance is prefixed with the active speaker's display name before it reaches the LLM. The agent's chat history then carries who-said-what context, which is critical for multi-participant calls (sales calls, panels, group standups) where the agent should address people by name and reason about turn-taking.

**What the agent sees**

Without `speaker_aware_responses` (default):

```
User: Can you summarise the action items so far?
User: I disagree with the budget number, can we revisit it?
```

With `speaker_aware_responses: true`:

```
User: [Rahul]: Can you summarise the action items so far?
User: [Priya]: I disagree with the budget number, can we revisit it?
```

The system prompt is automatically extended with a short instruction telling the LLM to use the names but not echo the bracketed prefix back in its replies.

**Customising the instruction (`speaker_aware_prompt`)**

The default instruction MeetStream appends is generic — "use the name to keep track of who said what, address participants by name when appropriate, do not include the bracketed prefix in your own replies". For most agents this is all you need.

When you want different behaviour — e.g. *only* address the most senior participant, summarise per-speaker at the end of the call, or treat the names purely as metadata that the agent should never mention out loud — provide your own `agent.speaker_aware_prompt`. It's appended to your `model.system_prompt` verbatim (with a leading blank line) whenever `speaker_aware_responses=true`. Limits:

- Max **2000 characters**.
- Must be a string. `null`, empty string, or omitted field → MeetStream uses its default.
- Has no effect when `speaker_aware_responses` is `false` (it's still accepted by the API so configs round-trip cleanly).

The bracketing mechanism (`[Rahul]: ...`) is unconditional once `speaker_aware_responses=true` — `speaker_aware_prompt` only governs *how the LLM interprets* the prefix, not whether it appears.

Example custom prompts:

```text
Each user message is prefixed with [Speaker Name]:. Track each participant's
viewpoint separately. When asked to summarise, group your summary by speaker.
Never repeat the bracketed prefix in your own replies and never address the
person by name unless they directly addressed you.
```

```text
Each user message starts with [Speaker Name]:. Treat the speaker label as
internal metadata only — do not address anyone by name in your replies and
do not mention the bracketed prefix. Use the speaker information only to
decide whose follow-up question you are answering.
```

```text
Messages are prefixed with [Speaker Name]:. The host is always [Rahul]; treat
their instructions as authoritative. Other participants are guests — answer
their questions briefly and defer back to the host. Strip the prefix from your
own replies.
```

**Speaker accuracy by platform**

| Platform | How the speaker is identified | Accuracy |
|---|---|---|
| Zoom | Per-user raw-audio callbacks tagged with SDK `node_id` | Strongest source attribution |
| Google Meet | Mixed audio labelled from the current active-speaker state; per-track CSRC audio is best effort | Approximate |
| Microsoft Teams | Per-participant tracks when available; otherwise mixed audio with dominant-speaker state | Exact at source in isolated-track mode; approximate on fallback |

The transcript prefix uses the latest speaker state when an utterance completes; it is not bound to a speaker-specific transcript span. Treat names as helpful conversational context, not forensic diarization. Rapid hand-offs, overlapping speech, and fallback mixed-audio paths can be misattributed.

**Compatibility**

- **STT providers**: Works with any provider you configure in `transcriber`. No diarization flags or special setup required — the speaker label comes from the bot itself, not the STT provider.
- **Wake word**: Compatible. Wake-word detection tokenises the transcript and ignores punctuation, so the bracketed prefix does not block matching.
- **Realtime mode**: Not part of the documented speaker-prefix contract. Realtime providers ingest raw audio directly; do not rely on this field for speaker attribution.
- **Custom functions / MCP tools**: Compatible. Tool calls are unaffected.

**Example — enable speaker-aware responses**

```json
{
  "mode": "pipeline",
  "agent_name": "Sales Coach",
  "agent": {
    "speaker_aware_responses": true,
    "speaker_aware_prompt": "Each user message is prefixed with [Speaker Name]:. Track each participant's viewpoint separately and group your summaries by speaker. Never repeat the bracketed prefix in your own replies."
  },
  "model": {
    "provider": "openai",
    "model": "gpt-4o-mini",
    "system_prompt": "You are a sales coach. Address participants by name.",
    "first_message": "Hi everyone, I'll listen in and help summarise."
  },
  "transcriber": { "provider": "deepgram", "model": "nova-2" },
  "voice": { "provider": "elevenlabs", "voice_id": "..." }
}
```

### Nested: `avatar`

Renders a video avatar on the bot's participant tile. Requires an Anam API key configured via the Integrations API (`config_type=avatar`, `provider=anam`). See [Virtual Avatars](/guides/mia/what-is-mia#virtual-avatars-anam) for capability details.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `enabled` | `boolean` | No | Whether the avatar is active. Default: `false` |
| `provider` | `string` | No | Avatar provider — currently `"anam"` only. Default: `"anam"` |
| `avatar_id` | `string` | Required when `enabled=true` and provider is `"anam"` | Anam avatar identifier. Fetch valid ids via `GET https://api.anam.ai/v1/avatars`. **Must be an `avatar_id`, not a `persona_id`** — both are UUIDs and this is a common source of errors |
| `avatar_model` | `string` | No | Optional Anam `avatarModel` override passed through to the persona config |
| `name` | `string` | No | Optional persona display name |

### Example Request — Pipeline Mode

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Meeting Assistant",
    "mode": "pipeline",
    "model": {
      "provider": "openai",
      "model": "gpt-4.1",
      "system_prompt": "You are a helpful meeting assistant. Summarize key decisions and track action items.",
      "first_message": "Hello! I am your meeting assistant. How can I help today?"
    },
    "voice": {
      "provider": "openai",
      "voice_id": "nova"
    },
    "transcriber": {
      "provider": "deepgram",
      "model": "nova-3",
      "language": "en"
    },
    "agent": {
      "response_modality": "audio"
    }
  }'
```

### Example Request — Realtime Mode

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Fast Voice Agent",
    "mode": "realtime",
    "model": {
      "provider": "openai",
      "model": "gpt-4o-realtime-preview",
      "system_prompt": "You are a concise, helpful assistant.",
      "voice": "alloy"
    }
  }'
```

### Example Request — Realtime Mode (xAI Grok)

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Grok Agent",
    "mode": "realtime",
    "model": {
      "provider": "xai",
      "system_prompt": "You are a witty and helpful meeting assistant.",
      "voice": "Ara"
    }
  }'
```

### Example Request — Realtime Mode (Google Gemini)

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Gemini Agent",
    "mode": "realtime",
    "model": {
      "provider": "google",
      "system_prompt": "You are a thoughtful meeting assistant.",
      "voice": "Puck",
      "thinking_config": {
        "include_thoughts": true,
        "thinking_budget": 1024
      }
    }
  }'
```

### Example Request — Pipeline Mode with Wake Words

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Wake Word Agent",
    "mode": "pipeline",
    "model": {
      "provider": "openai",
      "model": "gpt-4.1",
      "system_prompt": "You are a helpful meeting assistant. Only respond when addressed."
    },
    "voice": {
      "provider": "elevenlabs",
      "voice_id": "21m00Tcm4TlvDq8ikWAM",
      "model": "eleven_turbo_v2_5"
    },
    "transcriber": {
      "provider": "deepgram",
      "model": "nova-3"
    },
    "wake_word": {
      "enabled": true,
      "words": ["hey assistant", "hello bot"],
      "timeout": 30,
      "bypass_below_participants": 1,
      "max_listening_window": 600
    }
  }'
```

> The `bypass_below_participants: 1` above tells the bot to skip wake-word gating when only one human is in the meeting (you + bot). The moment a second human joins, gating resumes automatically.

### Example Request — Pipeline Mode with MCP Tools

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Action Agent",
    "mode": "pipeline",
    "model": {
      "provider": "openai",
      "model": "gpt-4.1",
      "system_prompt": "Listen for action items. When someone says to create a ticket, use the Linear tool to create it. Do not speak unless asked."
    },
    "voice": {
      "provider": "elevenlabs",
      "voice_id": "21m00Tcm4TlvDq8ikWAM",
      "model": "eleven_turbo_v2_5"
    },
    "transcriber": {
      "provider": "deepgram",
      "model": "nova-3"
    },
    "agent": {
      "response_modality": "action",
      "mcp_servers": [
        {
          "url": "https://your-mcp-gateway.example.com/mcp",
          "headers": { "Authorization": "Bearer <MCP_TOKEN>" },
          "allowed_tools": ["create_issue", "list_issues"]
        }
      ]
    }
  }'
```

### Example Request — Pipeline Mode with Custom Functions

Register two HTTPS endpoints as agent tools. The LLM sees them in the function-calling schema and can call them when the conversation warrants. The response body from `lookup_order` is captured into the session's dynamic vars so later prompt updates can reference `{{latest_order_status}}`.

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Support Agent",
    "mode": "pipeline",
    "model": {
      "provider": "openai",
      "model": "gpt-4.1",
      "system_prompt": "You are a support agent. When the caller asks about an order, call lookup_order. When they ask to open a ticket, call create_ticket.",
      "first_message": "Hi, I am your support assistant. How can I help today?"
    },
    "voice": { "provider": "openai", "voice_id": "nova" },
    "transcriber": { "provider": "deepgram", "model": "nova-3" },
    "agent": {
      "custom_functions": [
        {
          "name": "lookup_order",
          "description": "Look up the status of a customer order by order id.",
          "method": "POST",
          "url": "https://api.example.com/orders/lookup",
          "headers": {
            "Authorization": "Bearer <CUSTOM_FUNCTION_TOKEN>"
          },
          "parameters": {
            "type": "object",
            "required": ["order_id"],
            "properties": {
              "order_id": { "type": "string", "description": "Order id, e.g. ORD-1234" }
            }
          },
          "timeout_s": 20,
          "retries": 2,
          "response_cap_chars": 4000,
          "speak_during_execution": true,
          "speak_during_prompt": "One moment while I pull that up.",
          "response_variables": [
            { "name": "latest_order_status", "path": "data.order.status" }
          ]
        },
        {
          "name": "create_ticket",
          "description": "Create a support ticket. Call this when the caller explicitly asks to open a ticket.",
          "method": "POST",
          "url": "https://api.example.com/tickets",
          "parameters": {
            "type": "object",
            "required": ["subject", "body"],
            "properties": {
              "subject": { "type": "string" },
              "body": { "type": "string" },
              "priority": { "type": "string", "enum": ["low", "normal", "high"] }
            }
          },
          "speak_after_execution": false
        }
      ]
    }
  }'
```

### Example Request — Realtime Mode with Anam Avatar

Renders a video avatar on the bot's tile that lip-syncs to the agent's voice. Requires an Anam API key stored via the Integrations API (`config_type=avatar`, `provider=anam`). Use `GET https://api.anam.ai/v1/avatars` to list your available avatar ids.

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Avatar Agent",
    "mode": "realtime",
    "model": {
      "provider": "openai",
      "model": "gpt-realtime",
      "system_prompt": "You are a friendly customer success agent. Greet participants warmly and help them get started."
    },
    "voice": {
      "provider": "openai",
      "voice_id": "alloy"
    },
    "avatar": {
      "enabled": true,
      "provider": "anam",
      "avatar_id": "f0e7a8c4-1234-4abc-9def-0123456789ab"
    }
  }'
```

### Response — 200 OK

```json
{
  "message": "Agent configuration created successfully.",
  "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "agent_config": {
    "AgentConfigID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "UserID": "usr_xxxx",
    "AgentName": "Meeting Assistant",
    "Mode": "pipeline",
    "Model": {
      "provider": "openai",
      "model": "gpt-4.1",
      "system_prompt": "You are a helpful meeting assistant."
    },
    "Voice": { "provider": "openai", "voice_id": "nova" },
    "Transcriber": { "provider": "deepgram", "model": "nova-3", "language": "en" },
    "CreatedAt": "2026-04-22T10:00:00Z",
    "UpdatedAt": "2026-04-22T10:00:00Z"
  }
}
```

---

## GET /api/v1/mia

Retrieve a specific agent configuration by ID, or list all configurations for your account.

### Query Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_config_id` | `string` | No | Retrieve a specific configuration by ID |

If `agent_config_id` is omitted, all configurations for your account are returned.

### Example — List All Configurations

```bash
curl -X GET https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>"
```

**200 OK**
```json
{
  "agent_configs": [
    {
      "AgentConfigID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "UserID": "usr_xxxx",
      "AgentName": "Meeting Assistant",
      "Mode": "pipeline",
      "Model": { "provider": "openai", "model": "gpt-4.1", "system_prompt": "..." },
      "Voice": { "provider": "openai", "voice_id": "nova" },
      "Transcriber": { "provider": "deepgram", "model": "nova-3" },
      "CreatedAt": "2026-04-22T10:00:00Z",
      "UpdatedAt": "2026-04-22T10:00:00Z"
    }
  ],
  "count": 1
}
```

### Example — Get a Specific Configuration

```bash
curl -X GET "https://api.meetstream.ai/api/v1/mia?agent_config_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

**200 OK**
```json
{
  "agent_config": {
    "AgentConfigID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "UserID": "usr_xxxx",
    "AgentName": "Meeting Assistant",
    "Mode": "pipeline",
    "Model": { "provider": "openai", "model": "gpt-4.1", "system_prompt": "..." },
    "Voice": { "provider": "openai", "voice_id": "nova" },
    "Transcriber": { "provider": "deepgram", "model": "nova-3" },
    "Agent": { "response_modality": "audio" },
    "CreatedAt": "2026-04-22T10:00:00Z",
    "UpdatedAt": "2026-04-22T10:00:00Z"
  }
}
```

---

## PUT /api/v1/mia

Update an existing agent configuration. Only fields present in the request body are updated — omitted fields are left unchanged.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `agent_config_id` | `string` | Yes | ID of the configuration to update |
| `agent_name` | `string` | No | New display name |
| `mode` | `string` | No | Change mode: `"pipeline"` or `"realtime"`. Triggers full re-validation of all mode-specific fields. |
| `model` | `object` | No | Replace the model configuration |
| `voice` | `object` | No | Replace the voice configuration (pipeline mode) |
| `transcriber` | `object` | No | Replace the transcription configuration (pipeline mode) |
| `agent` | `object` | No | Replace agent behavior settings |
| `wake_word` | `object` | No | Replace wake word configuration |
| `audio` | `object` | No | Replace audio configuration |
| `avatar` | `object` | No | Replace avatar configuration |

> **Note:** Changing `mode` triggers full re-validation. Updating individual sections like `model`, `voice`, or `transcriber` validates that you have the required provider API keys but does not re-validate the full config structure.

### Example — Update the System Prompt

```bash
curl -X PUT https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "model": {
      "provider": "openai",
      "model": "gpt-4.1-mini",
      "system_prompt": "You are a concise meeting assistant. Keep answers brief."
    }
  }'
```

### Example — Update Agent Name and Wake Word

```bash
curl -X PUT https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "agent_name": "Scrum Bot",
    "wake_word": {
      "enabled": true,
      "words": ["hey scrum bot"],
      "timeout": 45
    }
  }'
```

### Example — Switch from Pipeline to Realtime Mode

```bash
curl -X PUT https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "mode": "realtime",
    "model": {
      "provider": "openai",
      "model": "gpt-4o-realtime-preview",
      "system_prompt": "You are a concise meeting assistant.",
      "voice": "alloy"
    }
  }'
```

### Response — 200 OK

```json
{
  "message": "Agent configuration updated successfully.",
  "agent_config": {
    "AgentConfigID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "UserID": "usr_xxxx",
    "AgentName": "Scrum Bot",
    "Mode": "pipeline",
    "Model": { "provider": "openai", "model": "gpt-4.1-mini", "system_prompt": "..." },
    "Voice": { "provider": "openai", "voice_id": "nova" },
    "Transcriber": { "provider": "deepgram", "model": "nova-3" },
    "WakeWord": { "enabled": true, "words": ["hey scrum bot"], "timeout": 45 },
    "UpdatedAt": "2026-04-22T11:00:00Z"
  }
}
```

---

## DELETE /api/v1/mia

Permanently delete an agent configuration. This action cannot be undone.

### Query Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_config_id` | `string` | Yes | ID of the configuration to delete |

### Example

```bash
curl -X DELETE "https://api.meetstream.ai/api/v1/mia?agent_config_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

**200 OK**
```json
{
  "message": "Agent configuration deleted successfully."
}
```

---

## Error Codes

| HTTP Status | When it occurs |
|-------------|----------------|
| `400` | Missing required field, invalid value, unsupported provider, or provider API key not configured |
| `403` | You do not own this agent configuration |
| `404` | Agent configuration or user not found |
| `405` | HTTP method not allowed on this path |
| `500` | Internal server error |

### Common Error Responses

**Missing provider API key**
```json
{
  "message": "API key not configured for: model.provider=openai (missing OpenAIAPIKey). Add it via the Integrations API first."
}
```

**Missing required field**
```json
{
  "message": "Missing agent_name."
}
```

**Invalid mode**
```json
{
  "message": "Invalid mode: batch. Must be 'pipeline' or 'realtime'."
}
```

**Unsupported provider**
```json
{
  "message": "Unsupported model provider: cohere. Supported: ['openai', 'anthropic', 'xai', 'google']"
}
```

**Invalid realtime voice**
```json
{
  "message": "Invalid OpenAI realtime voice: 'shimmy'. Supported: ['alloy', 'ash', 'ballad', 'cedar', 'coral', 'echo', 'fable', 'marin', 'nova', 'onyx', 'sage', 'shimmer', 'verse']"
}
```

**Invalid xAI voice**
```json
{
  "message": "Invalid xAI voice: 'Bob'. Supported: ['Ara', 'Eve', 'Leo', 'Rex', 'Sal']"
}
```

**Invalid Gemini voice**
```json
{
  "message": "Invalid Gemini voice: 'Zeus'. Supported: ['Aoede', 'Charon', 'Fenrir', 'Kore', 'Leda', 'Orus', 'Puck', 'Zephyr']"
}
```

**Access denied**
```json
{
  "message": "Access denied to this agent configuration."
}
```

---

## Server-Side Defaults (Pipeline Mode)

When creating a pipeline agent, the API automatically fills missing optional fields so the stored config matches what the internal dashboard produces. You can override any default by including the field explicitly.

| Section | Field | Default | Notes |
|---------|-------|---------|-------|
| `model` | `temperature` | `0.8` | |
| `model` | `first_message` | `""` | |
| `voice` | `model` | per-provider (see [voice defaults](#voice-model-defaults-by-provider)) | `openai` → `tts-1`, `elevenlabs` → `eleven_turbo_v2_5`, `xai` → `tts-1` |
| `voice` | `speed` | `1.0` | |
| `transcriber` | `language` | `"en"` | |
| `audio` | `sample_rate` | `24000` | Must be 24000 for OpenAI realtime compatibility |
| `audio` | `num_channels` | `1` | |
| `agent` | *(entire block)* | see [agent defaults](#nested-agent) | `turn_detection=vad`, `endpointing_mode=fixed`, `user_away_timeout=15`, etc. |

> **Field-name normalization:** `model.max_token` is auto-corrected to `model.max_tokens`. `transcriber.boost_words` is auto-corrected to `transcriber.boostwords`.

---

## Supported Providers

For the full list of supported realtime and pipeline providers, voices, models, and capabilities (wake words, interruption, VAD, MCP, echo cancellation, etc.), see the [MeetStream MIA Reference](/guides/mia/what-is-mia).

---

## Template Variables

Agent config prompts support **Mustache-style `{{variable}}` placeholders** in `model.system_prompt` and `model.first_message`. This lets you create a reusable agent config once and customize it per-bot at creation time by passing different variable values.

### How It Works

1. **Define placeholders** in your agent config prompt using `{{variable_name}}` syntax.
2. **Pass values** via the `agent_config_params` field when creating a bot.
3. **Placeholders are resolved** before the agent session starts — the LLM receives the fully substituted prompt.

Variable names can contain letters, digits, and underscores (`\w+`). Unresolved placeholders (no matching key in `agent_config_params`) are left as-is in the prompt.

### Example — Reusable Sales Agent

**Step 1: Create an agent config with template variables**

```bash
curl -X POST https://api.meetstream.ai/api/v1/mia \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "Sales Agent Template",
    "mode": "pipeline",
    "model": {
      "provider": "openai",
      "model": "gpt-4.1",
      "system_prompt": "You are a sales assistant for {{company_name}}. You are speaking with {{customer_name}}. Focus on {{product_line}}. {{extra_instructions}}",
      "first_message": "Hi {{customer_name}}, thanks for joining! I am here to help you with {{product_line}}."
    },
    "voice": {
      "provider": "openai",
      "voice_id": "nova"
    },
    "transcriber": {
      "provider": "deepgram",
      "model": "nova-3",
      "language": "en"
    }
  }'
```

**Step 2: Create bots with different variable values**

```bash
curl -X POST https://api.meetstream.ai/api/v1/bots/create_bot \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "meeting_link": "https://meet.google.com/abc-defg-hij",
    "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "agent_config_params": {
      "company_name": "Acme Corp",
      "customer_name": "Sarah",
      "product_line": "enterprise analytics",
      "extra_instructions": "Mention the Q2 discount if asked about pricing."
    }
  }'
```

The agent receives this resolved prompt:
> *You are a sales assistant for Acme Corp. You are speaking with Sarah. Focus on enterprise analytics. Mention the Q2 discount if asked about pricing.*

And the first message spoken to the meeting:
> *Hi Sarah, thanks for joining! I am here to help you with enterprise analytics.*

### Example — Fully Dynamic Prompt

You can use a single `{{prompt}}` placeholder to make the entire system prompt dynamic:

```bash
# Agent config with: "system_prompt": "{{prompt}}"

curl -X POST https://api.meetstream.ai/api/v1/bots/create_bot \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "meeting_link": "https://meet.google.com/abc-defg-hij",
    "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "agent_config_params": {
      "prompt": "You are a strict meeting moderator. Enforce a 2-minute speaking limit per person. Warn participants when they are approaching the limit."
    }
  }'
```

### `agent_config_params` Reference

| Field | Type | Description |
|-------|------|-------------|
| `agent_config_params` | `object` | Key-value map of template variable values. Keys must be strings matching `{{key}}` placeholders in the prompt. Values are coerced to strings. |

---

## Custom Functions

Custom functions let your agent call **any HTTPS endpoint you host** as a tool. Pair them with, or use them instead of, MCP: use MCP when you already run a multi-tool MCP server; use custom functions when you want to register a single endpoint without standing up MCP.

**What you get per function**
- JSON Schema arguments (the LLM generates correctly-typed args).
- Custom headers with `{{variable}}` substitution, plus automatic `X-Bot-ID` and `X-Agent-ID` context headers.
- Automatic retries on 5xx / network errors with exponential backoff.
- Configurable response cap so long payloads don't overwhelm the model.
- Optional **filler utterance** while the HTTP call runs (`speak_during_execution`) and optional **silent return** once it finishes (`speak_after_execution=false`).
- Optional **response variables** — values pulled from successful JSON responses via dot-notation paths. They are immediately available to later custom-function templates and to stored-prompt template rebuilds triggered by `update_mia`.

See [`agent.custom_functions[]`](#nested-agentcustom_functions) for the full field table and the [Custom Functions Guide](/guides/mia/mia-custom-configurations) for an end-to-end example.

---

## Mid-Call Updates (`update_mia`)

Request an asynchronous update to the agent's prompt, template variables, or wake-word state while the bot is live in a meeting. A successful HTTP response confirms that the command was accepted and forwarded; it does not wait for an application acknowledgement from the active agent session.

### Endpoint

```
POST https://api.meetstream.ai/api/v1/bots/{bot_id}/update_mia
```

| Parameter | Location | Required | Description |
|-----------|----------|----------|-------------|
| `bot_id` | Path | Yes | The bot ID returned from `create_bot` |
| `Authorization` | Header | Yes | `Token <YOUR_API_KEY>` |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `agent_config_params` | `object` | At least one | New template variable values to **merge** into existing params. Maximum 50 keys; values must be strings, numbers, or booleans. |
| `system_prompt` | `string` | At least one | A literal system prompt that replaces the agent's current instructions entirely (no template resolution). Max 32,000 characters. |
| `wake_word_enabled` | `boolean` | At least one | Toggle wake-word gating on or off live. Once set, this **supersedes** the automatic `bypass_below_participants` behaviour for the rest of the call — the user-supplied state wins regardless of meeting size. See [Live wake-word control](#live-wake-word-control). |
| `wake_words` | `array[string]` | At least one | Replace the wake-word phrase list live. Max **10 phrases**, each up to **64 characters** after trim. Empty array is rejected — use `wake_word_enabled: false` to disable the gate. |

> **Note:** At least one of `agent_config_params`, `system_prompt`, `wake_word_enabled`, or `wake_words` is required. If both `agent_config_params` and `system_prompt` are provided, `system_prompt` takes precedence. A supplied `system_prompt` is literal and is not template-resolved. The wake-word fields are applied first.

### Merge Behavior for `agent_config_params`

New params are **merged** into the bot's existing `AgentConfigParams` in DynamoDB — they do not replace them. For example, if the bot was created with:

```json
{ "company_name": "Acme Corp", "customer_name": "Sarah", "product_line": "analytics" }
```

And you send:

```json
{ "agent_config_params": { "customer_name": "John", "extra_instructions": "Offer a demo" } }
```

The merged result used for template resolution is:

```json
{ "company_name": "Acme Corp", "customer_name": "John", "product_line": "analytics", "extra_instructions": "Offer a demo" }
```

The original template from the agent config is re-resolved against the merged params.

### Example — Update Template Variables Mid-Call

```bash
curl -X POST "https://api.meetstream.ai/api/v1/bots/{bot_id}/update_mia" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_config_params": {
      "customer_name": "John",
      "extra_instructions": "The customer just asked about pricing — mention the Q2 discount."
    }
  }'
```

### Example — Replace the System Prompt Entirely

```bash
curl -X POST "https://api.meetstream.ai/api/v1/bots/{bot_id}/update_mia" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "system_prompt": "You are now in wrap-up mode. Summarize the key decisions from the meeting and list action items."
  }'
```

### Live wake-word control

`wake_word_enabled` and `wake_words` give you runtime control over the wake-word system without needing to update the agent config or restart the bot.

**Behaviour**

- `wake_word_enabled: true` forces the gate **on**: the agent stays gated even if the meeting drops below `bypass_below_participants` (e.g. a 1:1 call where the gate would normally auto-bypass). The agent waits for a wake phrase before responding.
- `wake_word_enabled: false` forces the gate **off**: the agent listens to every utterance regardless of meeting size. Useful for "always-on" modes, push-to-talk dashboards, or debugging.
- `wake_words: [...]` replaces the entire phrase list. Subsequent utterances are matched against the new list (whole-token, case-insensitive, punctuation-insensitive). Phrases configured at agent-config creation time are no longer matched.
- Either field is **sticky** for the rest of the session — it overrides the agent-config defaults and the participant-count bypass until the bot leaves the meeting (or you call `update_mia` again with a different value).
- Both fields are accepted in a single call. Phrases are applied first, then the on/off override, then any prompt update.

**Override semantics — important**

`wake_word_enabled` **supersedes** the automatic `bypass_below_participants` logic configured on the agent. Once you call `update_mia` with `wake_word_enabled`, the platform-side participant-count bypass is no longer consulted for that bot — your explicit setting is authoritative until the bot leaves. This lets you take full control from a dashboard or runtime workflow without fighting the platform.

**Examples**

Disable the gate for the rest of the call (always-on listening):

```bash
curl -X POST "https://api.meetstream.ai/api/v1/bots/{bot_id}/update_mia" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{ "wake_word_enabled": false }'
```

Re-enable the gate (e.g. when guests join the call):

```bash
curl -X POST "https://api.meetstream.ai/api/v1/bots/{bot_id}/update_mia" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{ "wake_word_enabled": true }'
```

Switch wake phrases mid-call (e.g. swap to a meeting-specific code phrase):

```bash
curl -X POST "https://api.meetstream.ai/api/v1/bots/{bot_id}/update_mia" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{ "wake_words": ["hey ada", "ok ada", "ada listen"] }'
```

Combined update — switch into always-on, replace wake phrases, and pivot the prompt in one call:

```bash
curl -X POST "https://api.meetstream.ai/api/v1/bots/{bot_id}/update_mia" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "wake_word_enabled": false,
    "wake_words": ["hey ada"],
    "system_prompt": "You are now in active assistant mode. Respond to every utterance."
  }'
```

**Validation errors (400)**

| Error | Cause |
|---|---|
| `wake_word_enabled must be a boolean (true or false)` | Non-bool value supplied. |
| `wake_words must be an array of strings` | Wrong type (string, object, etc.). |
| `wake_words cannot be empty — use 'wake_word_enabled': false to disable the gate` | Empty list. |
| `wake_words exceeds 10 phrase limit` | More than 10 entries. |
| `wake_words[N] cannot be empty after trim` | Whitespace-only entry. |
| `wake_words[N] exceeds 64 character limit` | Single phrase too long. |

> **Persistence**: live overrides are held in-memory on the agentic task. If the agentic task is replaced (rolling deploy), the bot reverts to the wake-word settings configured on its agent. To make a setting permanent, also update the agent config via the standard `PUT /api/v1/mia` endpoint.

### Response (200)

This response means **accepted for asynchronous delivery**, not confirmed application:

```json
{
  "status": "accepted",
  "bot_id": "83acdd72-3257-4b06-a2e9-0d879dc571ff",
  "command": "update_mia"
}
```

### Conditions

- The bot must have an active MIA agent session (created with `agent_config_id`).
- The bot must be in the meeting (`Joining` or `InMeeting` status).
- Rate limit: **30 bot-command requests per minute** per bot, shared with other commands on this endpoint.
- Works on all platforms: **Google Meet**, **Zoom**, **Microsoft Teams**.

### Error Responses

| Status | Meaning |
|--------|---------|
| `400` | Missing both `agent_config_params` and `system_prompt`, or invalid field types. |
| `401` | Missing or invalid API key. |
| `403` | Bot does not belong to your account. |
| `404` | Bot not found. |
| `409` | Bot is not currently in a meeting. |
| `429` | Rate limit exceeded (30/min per bot). |
| `503` | Bot is unreachable or has no active MIA session. |

---

## Using an Agent Config with a Bot

Pass `agent_config_id` when creating a bot to attach the agent to a meeting session. The agent becomes active as soon as the bot joins. WebSocket URLs for `socket_connection_url` and `live_audio_required` are auto-populated when `agent_config_id` is present — you do not need to provide them.

```bash
curl -X POST https://api.meetstream.ai/api/v1/bots/create_bot \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "meeting_link": "https://meet.google.com/abc-defg-hij",
    "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }'
```

To customize the prompt per-bot, add `agent_config_params` (see [Template Variables](#template-variables)):

```bash
curl -X POST https://api.meetstream.ai/api/v1/bots/create_bot \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "meeting_link": "https://meet.google.com/abc-defg-hij",
    "agent_config_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "agent_config_params": {
      "name": "John",
      "command": "welcome to the meeting"
    }
  }'
```

See the [Create Bot Payload Reference](../MeetStream_Create_Bot_Payload_Reference.md) for all available bot creation options.

---

## Related Guides

- [MIA Reference](/guides/mia/what-is-mia) — Full feature reference: modes, providers, wake words, MCP tool calling, interruption handling
- [Create an AI Agent (Dashboard)](/guides/mia/create-an-agent) — Step-by-step dashboard walkthrough with MCP server setup
- [Create Bot Payload Reference](../MeetStream_Create_Bot_Payload_Reference.md) — All `create_bot` fields including `agent_config_id`