---
title: "Get Speaker Sip Test"
method: GET
path: "/speakers/{speaker_id}/sip-test"
tags: ["speakers"]
---

# Get Speaker Sip Test

`GET /speakers/{speaker_id}/sip-test`

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

The newest SIP test on this speaker, or null if it has never been tested.

Polled by the result panel while the call is open, which is how the owner
sees `Terminated` and the platform's own disconnection reason land rather
than being told the test "succeeded" and left to wonder.

THIS GET WRITES, AND DELIBERATELY IS NOT AUDITED: `refresh_platform_view`
caches what the voice platform itself says about this tenant's own call —
its status, disconnection reason and duration — onto the test row,
best-effort, because there is no webhook for a test call and this poll is
one of only two things that ever re-ask. It records no operator decision and
changes nothing an operator did, so an `ActivityLogService` entry for it
would be an audit trail of the provider's opinion rather than of anybody's
action (round-2 review, accepted and recorded).

## Path parameters

- `speaker_id` string, required

## Response `200`

Successful Response

- SpeakerSipTestResponse: The result of one SIP test call. A 200 MEANS "THE HORN IS ON A CALL", NOT "THE TEST IS OVER": the request returns at connect and deliberately leaves the call up so the owner hears it. Poll `GET /speakers/{id}/sip-test` to watch it end. A `DELETE` on the same path hangs the call up early — the owner's release for a horn that is stuck, and the only one a test row has (the event-scoped hang-up cannot address it). `passed` is the two-signal check, minus the reservation: the device reported the call `Active` AND the voice platform reported the same call live. Either alone proves half of it — the platform connecting proves an agent is speaking into a call, the device being Active proves the horn is on a call, and it takes both to prove the agent is speaking OUT OF the horn.
  - `call_id` string, uuid, required: The call record for this test.
  - `speaker_id` string, uuid, nullable: The speaker that was tested.
  - `speaker_label` string, required: The speaker's display name.
  - `status` string, required: placing | connected | ended | failed.
  - `passed` boolean, required: True only when the device and the voice platform both reported this call live.
  - `summary` string, required: One sentence a person can act on.
  - `device_call_id` string, nullable: The device's own CallId, once it answered the dial.
  - `device_states` SipTestDeviceState[]: Every state the device reported, in order.
    - `state` string, required: The state the device reported, verbatim.
    - `at` string, required: When we observed it, ISO-8601 UTC.
    - `reason` string, nullable: What the device said about the transition, when it said anything.
  - `provider_call_id` string, nullable: The voice platform's call id.
  - `provider_status` string, nullable: The platform's own call status, verbatim.
  - `provider_disconnection_reason` string, nullable: Why the platform says the call ended.
  - `duration_ms` integer, nullable: The platform's measured call duration.
  - `provider_unreadable` boolean: True when the voice platform could not be read at all. NOT the same as `passed: false` with a status: it means we do not know what the platform saw, which is a different thing to do about it than a call the platform never received.
  - `signals_agreed_at` string, date-time, nullable: When the device and the platform first agreed the call was live. A HIGH-WATER MARK: once set it stays, because a call that has since ended still passed.
  - `auth_mode` string, nullable: Which auth mode the device accepted.
  - `playback_note` string, nullable: Set when the device could not confirm it had finished a clip and the owner went ahead anyway.
  - `device_error` SipTestDeviceError: The device's own refusal, quoted. THE SINGLE MOST USEFUL SENTENCE IN AN INSTALL. AXIS answers a refused `axcall:Call` with an HTTP 400 whose body names the fault — `Invalid SIPAccountId 'Gate horn'` is literally the mistake that cost a full day on site — and until this shipped the body was dropped and the console showed nothing but a failure. Bounded at 200 characters; headers are never quoted, and the body cannot carry device credentials (they exist only in the auth header).
    - `http_status` integer, nullable: The HTTP status the device answered with.
    - `body` string, nullable: A bounded excerpt of the device's error body.
  - `sip_account_id` string, nullable: Which SIP account the call was placed from; null means the device default.
  - `started_at` string, date-time, nullable: When the call was placed.
  - `ended_at` string, date-time, nullable: When the call ended, if it has.
  - `end_reason` string, nullable: Why the call ended.
  - `max_seconds` integer, required: The test call's duration cap — the watchdog hangs it up at this.
  - `result_version` integer: Shape version of the stored result this was rendered from. 0 means a row written before the stamp existed.

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