---
title: "Set Speaker Cameras"
method: PUT
path: "/speakers/{speaker_id}/cameras"
tags: ["speakers"]
---

# Set Speaker Cameras

`PUT /speakers/{speaker_id}/cameras`

## 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}/cameras`
- Auth: HTTP bearer

## Path parameters

- `speaker_id` string, required

## Request body

- SetSpeakerCamerasRequest: Replace the speaker's camera mappings with this exact set. Replace-set, not per-pair add/remove: the picker submits a set, and rewriting the whole set in one transaction makes priority reordering atomic. An empty list unmaps the speaker entirely — which immediately returns every affected camera to fail-closed behavior. ARMING IS RE-DECIDED ON EVERY SUBMISSION. Each mapping's `agent_trigger_enabled` is written from THIS request, so a mapping sent without the field lands disarmed (human-triggered only) regardless of what the row it replaces said — it is never inherited. A picker that round-trips mappings must send the flag back or it will disarm the agent on every camera it re-submits, which is the safe direction and the reason this is stated here rather than left to be discovered.
  - `mappings` SpeakerCameraMapping[]: The complete desired mapping set. Every camera must belong to the speaker's own site.
    - `camera_id` string, uuid, required: Camera whose field of view this speaker covers.
    - `priority` integer: Failover order for THIS camera: 0 is the primary, lower wins. Duplicates are allowed and break ties deterministically by mapping age.
    - `agent_trigger_enabled` boolean: Arm the AI agent to fire this speaker automatically for this camera. Default false = human-triggered only: operators can Talk Down, the agent's voice-down resolves nothing and fails closed exactly as an unmapped camera. Replace-set semantics: omitting this re-decides it as FALSE, it never inherits the previous row's value.

## Response `200`

Successful Response

- SpeakerMappingsResponse: This speaker's camera mappings, as they stand after the request. ARMING IS RE-DECIDED ON EVERY REPLACE-SET PUT AND IS NEVER INHERITED. The PUT rewrites the whole set, so each `agent_trigger_enabled` here is what THAT request asked for: a mapping submitted without the field comes back false (human-triggered only) regardless of what the row it replaced said. Read this payload as the authoritative new state — do not assume an omitted field left the previous value alone, because it did not.
  - `speaker_id` string, uuid, required: The speaker.
  - `mappings` SpeakerCameraMappingResponse[], required: Cameras this speaker covers, by priority.
    - `camera_id` string, uuid, required: Mapped camera.
    - `camera_label` string, required: The camera's display name.
    - `priority` integer, required: Failover order for that camera: 0 is the primary.
    - `agent_trigger_enabled` boolean, required: Whether the AI agent is armed to fire this speaker automatically for that camera. False (the default) is human-triggered only: operators can Talk Down, the agent's voice-down fails closed exactly as on an unmapped camera, and the policy ledger reports voice-down as unavailable there.

## 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)
