---
title: "Start Talk Session"
method: POST
path: "/speakers/{speaker_id}/talk-sessions"
tags: ["voice-sessions"]
---

# Start Talk Session

`POST /speakers/{speaker_id}/talk-sessions`

## Request

- Base URL: `https://api.verdun.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.verdun.ai/speakers/{speaker_id}/talk-sessions`
- Auth: HTTP bearer

Claim a speaker for live voice and hand back the socket credentials.

Talking to a speaker with NO camera mapping is allowed (owner decision
2026-08-25): an operator addresses a place, not a camera. Tenant scoping is
what contains it - `SpeakersService.get_speaker` runs
`ensure_parent_in_scope`, so a site-scoped operator cannot reach another
customer's speaker.

## Path parameters

- `speaker_id` string, required

## Request body

- StartVoiceSessionRequest: OPTIONAL body for POST /speakers/{id}/talk-sessions. Absent (or empty) = today's behaviour: a session addressed to a place, with no alarm. With `event_id` the session is tied to that alarm, which is what lets the Escalations timeline show it and the after-voice-down recording attach to it.
  - `event_id` string, uuid, nullable: The alarm this talk is about. Must be in the caller's scope. The speaker must share the alarm camera's current site and parent; a camera-speaker mapping is not required for human Live Talk.
  - `camera_id` string, uuid, nullable: Optional; must equal the alarm's camera. Requires event_id.

## Response `200`

Successful Response

- StartVoiceSessionResponse: A claimed speaker and the credentials to open the audio socket. `ticket` is the ONLY time the plaintext ticket exists anywhere - it is stored on the row as a SHA-256 digest and can never be re-read. A client that loses it must start a new session.
  - `session_id` string, uuid, required: The session that now holds this speaker.
  - `speaker_id` string, uuid, required: The speaker being talked through.
  - `speaker_label` string, required: The speaker's display name.
  - `ws_url` string, required: Path to open the audio WebSocket on. Present the ticket as `?ticket=`.
  - `ticket` string, required: Single-use, short-lived credential for the audio socket. The browser WebSocket API cannot send an Authorization header, so this stands in for the bearer token. Shown once.
  - `expires_at` string, date-time, required: After this the ticket is dead and the session is reaped.
  - `max_seconds` integer, required: Hard cap on the session. The server stops it regardless of the client.
  - `idle_seconds` integer, required: Silence for this long ends the session - an open mic never dangles.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/verdun/apis/verdun-api.md) - [All operations](https://skmtc.dev/verdun/apis/verdun-api/llms.txt) - [OpenAPI document](https://skmtc.dev/verdun/apis/verdun-api/revisions/35a2a6ebedda?raw)
