---
title: "Read one call, optionally waiting for a terminal status"
method: GET
path: "/v1/calls/{id}"
---

# Read one call, optionally waiting for a terminal status

`GET /v1/calls/{id}`

## Request

- Base URL: `https://volai.cz`
- URL: `https://volai.cz/v1/calls/{id}`
- Auth: HTTP bearer

The detail of a call. Optionally, `waitSecs` (see the callout below) makes the server wait for the result instead of you polling. For calls with an agent, it also includes `transcript` (a turn-by-turn transcript, each turn with an optional `timeInCallSecs` field - seconds since the call started, missing if the provider didn't time-stamp that turn; an agent turn the caller interrupted additionally carries `interrupted: true` and its `message` is still the full planned text, volai's own engine only) and `summary` (a short summary) - see [Webhooks](https://volai.cz/en/docs/webhooks) for the same shape delivered automatically once the call ends. Both the list and the detail also carry `answeredBy` (OUTBOUND calls only: `human`, `voicemail`, `ivr` (an automated voice menu answered; the engine hangs up right away), or `unknown` when the engine reached no decision or the transcript is missing; inbound calls omit the field, because a brief caller reply is not a voicemail). The engine decides with `human`, `voicemail`, and `ivr`; `unknown` means the engine reached no decision before its detection window closed, and since 1.33.0 it stays `unknown` (earlier the transcript-based estimate replaced it, and that estimate treated a short reply such as "Yes." after the intro as a voicemail). The transcript-based estimate (`human` or `voicemail`, `unknown` for an empty transcript; it never detects a voice menu) applies only to calls without an engine value. An outbound call handled by volai's own voice engine also carries `voicemailReason` (`phrase`, `long_monologue`, `beep`, `human_reply`, `ivr_phrase`, or `digits` - `human_reply` means a person picked up with a reply so short the detector noted it (not that it was a voicemail), `ivr_phrase` is a voice menu phrase, `digits` a carrier greeting reading the called number digit by digit), `voicemailMessageLeft` (the engine read the configured message into the voicemail), and `voicemailDetectedAtSecs` (seconds from pickup until the engine's detector reached a decision - even on a call a person answered) - all three fields come only from the engine; ElevenLabs's transcript-based classification (`answeredBy` without an explicit value) doesn't know the reason or the timing. An inbound or outbound call on the engine also carries `optOutRequested: true` when the remote participant explicitly asked not to be called again (for example "do not call me", even in the last seconds after the farewell) - the number is then on the account's do-not-call list automatically (`GET /v1/dnc`) and the task retry policy schedules no further attempt; a call without such a reply has no such key. It also carries `endReason` (`completed`, `no_answer`, `busy`, `rejected`, `capacity`, `blocked`, `loop_guard`, `credit_blocked`, `suspended`, `engine_error`, `caller_loop`, `failed`), and `kind` (`agent`, `bridge`, `relay`, `inbound`, `transfer`, `sip`, `ring`) - see the table below. A ring (`kind: "ring"`) also carries a `ring` block (`requestedSecs`, `outcome`, `rangSecs`) - see `POST /v1/rings`. The tools-and-recordings wave added two more fields: `data` (what the agent captured from the call per its `dataFields`; a `null` value means it wasn't mentioned) and `hasRecording` (the call has a recording available for download, see the endpoint below). Older calls don't have these fields and they're missing from the response. `durationSecs` is in seconds; for calls handled by volai's own engine it can be a decimal number (rounded to two decimal places). The response carries the account owner's own annotations, always present, `null` when unset: `note` (string), `flag` (`{reason, flaggedAt} | null`), `handledAt` (Unix ms or `null`) and `goal` (`{result: "success"|"failure"|"unknown", rationale, reason} | null`, filled in only once the agent's goal was evaluated; `reason` is `"no_caller_speech"|"evaluation_error"|null` and says why the result came out "unknown" - `null` for a genuinely unclear result) - see `PATCH /v1/calls/{id}` below. The response also always carries `hasConversation` (`boolean | null`) - whether the call actually had a conversation with the caller; `false` for a call that didn't connect, voicemail, or a voice menu, `null` for an older record without enough signal to decide. A call for an agent with phases (workflow nodes plan) handled by volai's own voice engine (`provider: "engine"`) also carries `workflowPath` - see the Call phases (workflow) section under agents above; a call on an agent hosted on ElevenLabs never carries the field, even when it went through phases, because only the engine's post-call writes it. A call handled by an engine build from 15 Oct 2026 on also carries, in the detail (not in the list), an `engine` block with `protectedUtterances` and `protectedUtterancesCount`: utterances of the person who answered that the engine dropped during the greeting window - what they said while the agent spoke its first line ("Hello?", their name, or anything inside `firstMessageProtectSecs`) and the engine deliberately did not take, so it is NOT in the transcript and the agent did not react to it; an agent-only transcript with a non-empty list therefore means the person did answer and speak. Each item has `timeInCallSecs` (start of the speech in the recording, absent when the engine does not know it), `atSecs` (when the engine finished hearing it, seconds from the start of the call, always), `message` (up to 200 characters), `words` and `reason` (`first_message_protect`, `greeting_courtesy` or `greeting_identification`; open list). At most 10 items, `protectedUtterancesCount` counts them all; a call with nothing dropped carries `[]` and `0`, older calls and agents hosted on ElevenLabs have no `engine` key at all. The same block is in the `call.*` webhook.

## Path parameters

- `id` string, required

## Query parameters

- `waitSecs` integer

## Response `200`

Call detail

- object
  - `call` object, required
    - `id` string, required
    - `direction` 'in' | 'out', required
    - `from` string, required
    - `to` string, required
    - `status` 'initiated' | 'ringing' | 'in_progress' | 'completed' | 'failed' | 'missed' | 'no_answer', required
    - `startedAt` number, required
    - `durationSecs` number
    - `priceHal` number
    - `agentId` string
    - `callbackOf` object
      - `callId` string, required
      - `taskId` string
      - `taskItemId` string
    - `source` 'api' | 'mcp' | 'portal' | 'inbound', required
    - `kind` 'agent' | 'bridge' | 'relay' | 'inbound' | 'transfer' | 'sip' | 'ring'
    - `ring` object: Present only on a ring attempt (`kind` is `ring`): how long ringing was requested, how the attempt ended and how long the target rang. `outcome` and `rangSecs` are absent while the attempt is still running.
      - `requestedSecs` integer, required: Seconds of ringing that were requested for this attempt: the ringSecs of the request, or 10 when it was omitted.
      - `outcome` 'rang' | 'ended_early' | 'answered' | 'unknown': How a ring attempt ended. `rang`: the target rang and volai hung up when the requested time ran out. `ended_early`: the call ended on its own before volai hung up (the target declined it, was busy or unreachable). `answered`: the target picked up and volai hung up at once; the connected seconds are billed on top at the outbound call rate. `unknown`: the result could not be determined (for example the call never showed up as ringing) and is settled later from the carrier's call record. A gate that opens when it sees the call usually ends as `rang` or `ended_early`; `answered` is the exception.
      - `rangSecs` number: How long the target rang, in seconds. First volai's own measurement, replaced by the carrier's figure once its call record has been processed. The carrier counts the ringing from the moment the order is placed, so its figure is usually 1 to 3 seconds longer than the requested `ringSecs`.
    - `answeredBy` 'human' | 'voicemail' | 'ivr' | 'unknown': Outbound calls only: `human`, `voicemail`, `ivr` (an automated voice menu answered; the engine hangs up), or `unknown` when the engine reached no decision or the transcript is missing. Inbound calls omit the field, because a brief caller reply is not a voicemail.
    - `voicemailReason` 'phrase' | 'long_monologue' | 'beep' | 'human_reply' | 'ivr_phrase' | 'digits'
    - `voicemailMessageLeft` boolean
    - `optOutRequested` true: Calls on the built-in engine, in either direction: the remote participant explicitly asked not to be called again (for example "už mi nevolejte" / "do not call me"), even in the last seconds after the farewell. Present only as `true`; this triggers protection of the remote participant's number in the account's do-not-call list (outbound to, inbound from).
    - `voicemailDetectedAtSecs` number
    - `endReason` 'completed' | 'no_answer' | 'busy' | 'rejected' | 'capacity' | 'blocked' | 'loop_guard' | 'credit_blocked' | 'suspended' | 'failed' | 'engine_error' | 'caller_loop'
    - `workflowPath` object[]: Path of the call through the agent's workflow nodes, if any. Written only by volai's own voice engine's post-call (provider: "engine"); a call on an agent hosted on ElevenLabs never carries this field, even when the agent has phases and the call went through them. Also absent when the agent has no workflow configured.
      - `node` string, required
      - `label` string, required
      - `viaEdge` string, nullable, required: Id of the edge this step entered through; null for the entry step.
      - `turnIndex` number, required
      - `at` number, required: Unix ms timestamp of this step.
      - `enterPhraseSpoken` boolean, required
    - `data` object
    - `hasRecording` boolean
    - `note` string, nullable, required
    - `flag` object, nullable, required
      - `reason` string, required
      - `flaggedAt` number, required
    - `handledAt` number, nullable, required
    - `goal` object, nullable, required
      - `result` 'success' | 'failure' | 'unknown', required
      - `rationale` string, nullable, required
      - `reason` 'no_caller_speech' | 'evaluation_error', nullable, required: Why the result is `unknown` - `no_caller_speech` (the caller never spoke) or `evaluation_error` (the evaluation itself failed); `null` for a genuinely unclear result or an older record without this field.
    - `hasConversation` boolean, nullable, required: Whether the call had an actual conversation with the caller. `false` means reliably no conversation (not connected, voicemail, a voice menu answered, or the engine explicitly reported the caller never spoke). `null` means it cannot be determined (an older record with neither a transcript nor the signal).
    - `rating` object, nullable, required: One-click call rating from the portal, the post-call e-mail, PATCH /v1/calls/{id} or MCP annotate_call. null means not rated yet.
      - `value` 'good' | 'bad', required
      - `reason` 'misunderstood' | 'wrong_answer' | 'silence' | 'hung_up_early' | 'other'
      - `note` string
      - `at` number, required
      - `source` 'portal' | 'email' | 'api' | 'mcp', required
    - `missedSms` object: Present once the missed-call SMS was actually sent (or queued and later sent during quiet hours) for this call.
      - `sentAt` number, required
      - `messageId` string, required
    - `transcript` object[]
      - `role` 'agent' | 'caller', required
      - `message` string, required
      - `timeInCallSecs` number
      - `interrupted` boolean: true on an agent line the caller interrupted, so they did not hear all of it; message still holds the full planned text. Absent on every other line, and on calls handled by ElevenLabs.
    - `summary` string
    - `engine` object: Facts the volai engine measured about the call. Present only on calls handled by an engine build from 15 Oct 2026 on; absent on older engine calls and on agents hosted on ElevenLabs. The same block is in the call.* webhook payload.
      - `protectedUtterances` object[], required: Utterances of the person who answered that the engine dropped on purpose during the greeting window (a "Hello?" or their name while the first line played, or any reply inside firstMessageProtectSecs). They are not in the transcript and the agent did not react to them, so an agent-only transcript with a non-empty list means the person did answer and speak. At most 10 items, in call order; [] when nothing was dropped.
        - `timeInCallSecs` number: Seek position of the start of the utterance in the recording, in seconds (same convention as transcript turns). Absent when the engine does not know the start.
        - `atSecs` number, required: When the engine finished hearing the utterance, in seconds from the start of the call. Always present.
        - `message` string, required: What the person who answered said, up to 200 characters. Not part of the transcript; the agent never heard it.
        - `words` number, required: Word count of the full utterance, counted before the 200-character cut.
        - `reason` string, required: Why the engine dropped it: first_message_protect (inside firstMessageProtectSecs), greeting_courtesy (a courtesy word such as "Hello?" while the first line played) or greeting_identification (the person stating their name). Open list; tolerate unknown values.
      - `protectedUtterancesCount` integer, required: Number of all dropped utterances, including any beyond the 10 listed.
  - `stillRunning` boolean

## Other responses

- `400`: Error codes: validation (request).
- `401`: Error codes: unauthorized (request).
- `403`: Error codes: account_suspended (account).
- `404`: Error codes: call_not_found (account).
- `429`: Error codes: rate_limited (busy).
- `500`: Error codes: internal_error (service).

---

[API](https://skmtc.dev/volai/apis/volai-rest-api.md) · [All operations](https://skmtc.dev/volai/apis/volai-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/volai/apis/volai-rest-api/revisions/12029b05e2fa?raw)
