---
title: "Get Camera Speakers"
method: GET
path: "/cameras/{camera_id}/speakers"
tags: ["speakers"]
---

# Get Camera Speakers

`GET /cameras/{camera_id}/speakers`

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

## Path parameters

- `camera_id` string, required

## Response `200`

Successful Response

- CameraSpeakersResponse: Which speakers serve a camera, in the order delivery would try them. `speakers` is the MANUAL view: every live mapping, which is exactly what an operator's Talk Down would announce on. It is resolved through the same query builder delivery uses, so it is what would actually announce — not a tidied-up list. The AI agent's view is narrower, because a mapping arms the operator while `agent_trigger_enabled` arms the agent (default false). Rather than hide that, `agent_enabled_speaker_ids` names the subset the agent's automated voice-down would resolve — the same subset the policy ledger reports availability from. An empty list there with a non-empty `speakers` means "humans only on this camera", which is the pilot's posture by design.
  - `camera_id` string, uuid, required: The camera.
  - `speakers` SpeakerResponse[], required: Mapped, enabled, live speakers in failover order — what an operator's Talk Down would announce on.
    - `id` string, uuid, required: The speaker record ID.
    - `site_id` string, uuid, required: The site this speaker belongs to.
    - `parent_id` string, uuid, required: The client this speaker belongs to.
    - `label` string, required: Display name.
    - `brand` 'axis', required
    - `model` 'axis_c1310_e' | 'axis_c1210_e' | 'axis_c1310_e_mk2'
    - `host` string, required: IP address of the speaker (IPv4 or IPv6 literal), in canonical form. Hostnames are not supported in v1.
    - `port` string, required: HTTPS port.
    - `username` string, required: Device account username (the password is never returned).
    - `transport` 'direct_https' | 'direct_http' | 'nvr_proxy', required
    - `clip_id` string, nullable: Id of the pre-loaded deterrent clip.
    - `clip_params` object, nullable: Playback parameters.
    - `enabled` boolean, required: Whether delivery and the health poll consider this speaker.
    - `sip_enabled` boolean: Whether the AI voice agent may place a SIP call to this speaker.
    - `sip_account_id` string, nullable: Which of the device's SIP accounts the agent's call is placed from; null means the device default.
    - `mic_enabled` boolean: Whether this unit's microphone is live, which decides whether the agent waits for a reply.
    - `onboarding_checklist` object, nullable: The device-setup checklist: the owner's own attestations under `items`, each stamped server-side. An absent key means not confirmed. The one item the device answers for itself is NOT stored here — read it live from `GET /speakers/{id}/sip-accounts`.
    - `agent_armed_camera_count` integer, nullable: How many of this speaker's camera mappings are ARMED for the AI agent. Zero means nothing will ever announce here, however the device is configured.
    - `last_sip_test` LastSipTest: The headline of the newest SIP test on a speaker. `passed` is the two-signal check — the device reported the call Active AND the voice platform reported the same call live. The full timeline lives on `GET /speakers/{id}/sip-test`; this is what a list row needs to say whether a horn is armed.
      - `at` string, date-time, nullable: When the test was placed.
      - `passed` boolean, required: True only when both signals agreed.
      - `call_id` string, uuid, required: The call record, for the detail view.
      - `summary` string, required: One sentence a person can act on.
    - `map_x` number, nullable: Normalized floor-plan x.
    - `map_y` number, nullable: Normalized floor-plan y.
    - `map_lat` number, nullable: Geographic latitude of the speaker pin.
    - `map_lng` number, nullable: Geographic longitude of the speaker pin.
    - `map_location_label` string, nullable: Operator-facing location prose.
    - `map_heading` number, nullable: Direction a horn faces, degrees clockwise from map-up; null = not aimed (always null for an omnidirectional ceiling unit).
    - `healthy` boolean, nullable: Last health-poll result.
    - `last_healthcheck_at` string, date-time, nullable: When the speaker was last polled.
    - `health_error` string, nullable: Why the last health poll failed: unreachable (no HTTP answer), auth_rejected (the device answered 401 to the stored credentials), not_a_speaker (something answered, but not an Axis device API - e.g. a router page), clip_missing (the configured clip id is not on the device), or error. Null when healthy or never checked.
    - `device_serial` string, nullable: Serial number of the device last seen at this host:port, read without credentials. Compare it across speakers to tell two units behind one IP apart. Last known value; a failed poll keeps it.
    - `device_product` string, nullable: Product name of the device last seen at this host:port (ProdFullName, else ProdNbr). Last known value.
    - `device_firmware` string, nullable: Firmware version of the device last seen at this host:port. Last known value.
    - `device_identity_at` string, date-time, nullable: When the device identity above was last read successfully.
    - `created_at` string, date-time, nullable: When the speaker was registered.
    - `updated_at` string, date-time, nullable: When the speaker was last edited.
  - `agent_enabled_speaker_ids` string[], required: Subset of speakers[].id that the AI agent is armed to fire automatically for this camera. Empty means the camera is human-triggered only: the agent's voice-down fails closed there exactly as on an unmapped camera.

## 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/a19366be50a3?raw)
