# Voice

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/http-api/voice/
> Summary: The voice endpoints of the Tracon HTTP API — 8 operations.

8 operations. `{prefix}` is the route prefix passed to
`MapTracon`; the template uses `/tracon`.

## GET {prefix}/api/voice/health

**Operation ID:** `TraconVoiceHealth`

**Checks the voice provider's availability.**

The check does not incur cost: no speech is generated, only the available voices are read.

**Authorization:** bearer authentication; `Reader` role policy when that policy is registered; `PlatformRead` API-key scope.

| Response | Body | Headers |
|---|---|---|
| **200** OK | `application/json` → [`VoiceHealth`](/http-api/schemas/voicehealth/) | — |

## POST {prefix}/api/voice/live/sessions

**Operation ID:** `TraconLiveVoiceCreate`

**Creates a provider-hosted live voice session.**

Relays the media peer's SDP offer to the provider and returns its answer, so the raw API key never reaches the browser. Tracon attaches a server-side control connection to the same session and turns the work the model delegates into ordinary runs. The tenant's egress policy and its own provider binding apply as for a model call: 403 when the policy does not allow the live provider, when the tenant's binding for it has no value or sets an endpoint override, or when the provider cannot use the tenant's credential. Returns 501 when no live voice provider is registered.

**Authorization:** bearer authentication; `Operator` role policy when that policy is registered; `RunsWrite` API-key scope.

**Request body** (required):

- `application/json` → [`LiveVoiceSessionCreateRequest`](/http-api/schemas/livevoicesessioncreaterequest/)

| Response | Body | Headers |
|---|---|---|
| **200** OK | `application/json` → [`LiveVoiceSessionCreateResponse`](/http-api/schemas/livevoicesessioncreateresponse/) | — |
| **400** Bad Request | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **403** Forbidden | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **404** Not Found | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **429** Too Many Requests | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **501** Not Implemented | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **502** Bad Gateway | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |

## GET {prefix}/api/voice/live/sessions/{voiceSessionId}

**Operation ID:** `TraconLiveVoiceStatus`

**Reports a live voice session's state and measurement.**

The state is 'pending' until media is observed, then 'active', then 'ended'. The duration is the provider's own number: Tracon does not carry a live session's media and does not invent a duration.

**Authorization:** bearer authentication; `Reader` role policy when that policy is registered; `PlatformRead` API-key scope.

| Parameter | In | Required | Type | Description and rules |
|---|---|---|---|---|
| `voiceSessionId` | path | yes | `string (uuid)` | — |

| Response | Body | Headers |
|---|---|---|
| **200** OK | `application/json` → [`LiveVoiceSessionStatusResponse`](/http-api/schemas/livevoicesessionstatusresponse/) | — |
| **404** Not Found | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |

## DELETE {prefix}/api/voice/live/sessions/{voiceSessionId}

**Operation ID:** `TraconLiveVoiceClose`

**Closes a live voice session and writes its record.**

Cancels any delegation still running, writes the session record with its measured duration and cost, and drops the provider connection. A session another tenant owns answers 404, byte for byte the answer a session that does not exist gets.

**Authorization:** bearer authentication; `Operator` role policy when that policy is registered; `RunsWrite` API-key scope.

| Parameter | In | Required | Type | Description and rules |
|---|---|---|---|---|
| `voiceSessionId` | path | yes | `string (uuid)` | — |

| Response | Body | Headers |
|---|---|---|
| **204** No Content | — | — |
| **404** Not Found | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |

## GET {prefix}/api/voice/providers

**Operation ID:** `TraconVoiceProviders`

**Lists the registered speech providers.**

Each entry is a synthesizer or a transcriber: its registration name (null for the default), its kind, the provider name a tenant's egress policy and provider bindings use, and whether it can call the service with a tenant's own credential. Reading the list calls no provider. An empty list means no speech provider is registered.

**Authorization:** bearer authentication; `Reader` role policy when that policy is registered; `AgentsRead` API-key scope.

| Response | Body | Headers |
|---|---|---|
| **200** OK | `application/json` → array of [`SpeechProviderDescriptor`](/http-api/schemas/speechproviderdescriptor/) | — |

## GET {prefix}/api/voice/sessions

**Operation ID:** `TraconVoiceSessions`

**Lists the summary record of real-time speech connections.**

The record does NOT contain audio: it only carries duration, turn count, and metering. If the speech layer is not enabled, the list is empty.

**Authorization:** bearer authentication; `Reader` role policy when that policy is registered; `RunsRead` API-key scope.

| Parameter | In | Required | Type | Description and rules |
|---|---|---|---|---|
| `agentName` | query | no | `string` | — |
| `sessionId` | query | no | `string` | — |
| `skip` | query | no | `integer (int32)` | pattern `^-?(?:0\\|[1-9]\d*)$` |
| `take` | query | no | `integer (int32)` | pattern `^-?(?:0\\|[1-9]\d*)$` |

| Response | Body | Headers |
|---|---|---|
| **200** OK | `application/json` → array of [`VoiceSessionRecord`](/http-api/schemas/voicesessionrecord/) | — |

## POST {prefix}/api/voice/speak

**Operation ID:** `TraconVoiceSpeak`

**Synthesizes speech from text and saves it as an attachment.**

This is an operator action and is NOT tied to a run; the metering is not written to tool_invocations, it is returned in the response. If persistent metering is required, use the agent's `speak` tool. The optional 'provider' field names a synthesizer registered with AddSpeechSynthesizer; without it the default synthesizer is used. Returns 400 for an unknown name, 403 when the tenant's egress policy does not allow the provider or the tenant has its own credential that the provider cannot use (the call is not made on the setup credential), and 501 when no default synthesizer is registered.

**Authorization:** bearer authentication; `Operator` role policy when that policy is registered; `RunsWrite` API-key scope.

**Request body** (required):

- `application/json` → [`SpeakRequest`](/http-api/schemas/speakrequest/)

| Response | Body | Headers |
|---|---|---|
| **200** OK | `application/json` → [`SpeakResponse`](/http-api/schemas/speakresponse/) | — |
| **400** Bad Request | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **403** Forbidden | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **501** Not Implemented | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **502** Bad Gateway | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |

## GET {prefix}/api/voice/voices

**Operation ID:** `TraconVoiceList`

**Lists the available voices.**

The list comes from the speech provider, not from Tracon; the identifiers it returns are the values the speak endpoint and the agent's 'speak' tool accept. The optional 'provider' query parameter names a synthesizer registered with AddSpeechSynthesizer; without it the default synthesizer is used. Returns 400 for an unknown name, and 403 when the tenant's egress policy does not allow the provider or the tenant has its own credential that the provider cannot use. When no default synthesizer is registered (UseVoice was never called), the response is 501 rather than 404, so a missing configuration is not mistaken for a wrong address. A provider that fails while listing its voices is 502, as for the speak endpoint.

**Authorization:** bearer authentication; `Reader` role policy when that policy is registered; `AgentsRead` API-key scope.

| Parameter | In | Required | Type | Description and rules |
|---|---|---|---|---|
| `provider` | query | no | `string` | — |

| Response | Body | Headers |
|---|---|---|
| **200** OK | `application/json` → array of [`VoiceDescriptor`](/http-api/schemas/voicedescriptor/) | — |
| **400** Bad Request | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **403** Forbidden | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **501** Not Implemented | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
| **502** Bad Gateway | `application/problem+json` → [`ProblemDetails`](/http-api/schemas/problemdetails/) | — |
