> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sempera.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Live calls and live transcripts

> The roster of calls in progress, one call's transcript so far and the workspace's active calls, each as a snapshot frame you read again to see a call move.

Three routes show what is happening on an agent's phone line and in its browser conversations right now: the roster of calls in progress, the turns spoken so far on one of them, and a workspace-wide list of active calls. Each answers a **snapshot**. The `stream` routes answer one Server-Sent Events frame and close the connection; there is no push, so read again (every few seconds is the pace the App uses) to see a call move.

All three need `calls:read`, any role. Listening in, stopping and taking over a live call are supervisor actions in the Sempera App; there is no `/v1` route for them.

| Route | Answers |
| - | - |
| `GET /v1/live-calls/stream?agent_id=` | One `roster` frame: the agent's calls in progress |
| `GET /v1/live-calls/transcript/stream?agent_id=&room=` | One `transcript` frame: the turns so far of one call |
| `GET /v1/calls/active` | The workspace's active calls as JSON, in the compatibility envelope |
| `GET /v1/calls/active/stream` | The same read as one `snapshot` frame |

## The roster

`agent_id` is required (`400 validation_failed` without it) and must be an agent the credential can read (`404 not_found` otherwise). The answer is `200 text/event-stream` with one frame:

```text theme={null}
event: roster
data: {"client": "northwind-barbers", "live": [ ... ], "media_server": true, "supervisor_modes": { ... }}
```

Each item of `live` is a call in progress, oldest first: `room` (its id, the value to pass as `room` below), `client` (the agent id), `mode`, `workspace_id`, `agent_version_id`, `language`, `caller` and `line` (numbers masked to their last four digits, `null` when unknown), `channel` (`phone` on a real phone line), `started_at` (Unix seconds), `elapsed_s`, `participants`, `recording_indicator` (always `true`), `sempera_call_id`, `engines` and the internal correlation identifiers a support request may quote. A room with nobody in it is not a call and is not listed. `supervisor_modes` says which supervisor actions the App offers and why any is not offered.

`engines` says what the call runs on: `llm` is the Sempera model id of the call's language model, or `null` when that model has none; `stt` and `tts.provider` are the speech recognition and voice engines, each named by its Sempera model id when the call uses a published Sempera model, `sempera-cloud-speech-recognition` or `sempera-cloud-voice` for an engine a cloud provider hosts for Sempera, and `null` when there is no Sempera name to give; `tts.voice` is the voice.

When Sempera's live call service cannot be reached the answer is still `200`, with `"live": []`, `"media_server": false` and `"error": "media server unreachable: <error type>"`. An empty roster with `media_server: true` means no call is in progress.

## One call's transcript

`room` is a `room` from the roster; it is required, as is `agent_id`. The frame is:

```text theme={null}
event: transcript
data: {"room": "<room>", "live": true, "turns": [{"role": "caller", "text": "..."}, {"role": "agent", "text": "...", "interrupted": true}]}
```

`turns` are the turns spoken so far, in order, each with a `role` (`caller` or `agent`) and its `text`; an agent turn the caller cut off carries `"interrupted": true`. There is nothing else on a turn, and the list is empty until the first turn is written. The route answers a frame for every outcome, not the standard error envelope ([Errors and limits](https://docs.sempera.org/errors-and-limits.md)): the frame's data is `{"error": "..."}` with status `400` when `room` is missing, `409` when the room is not a call in progress for this agent (it ended, or belongs to another agent) and `200` when Sempera's live call service cannot be reached (`media server unreachable: <error type>`). A missing `agent_id`, or one the credential cannot read, is refused with the standard envelope as for the roster.

A finished call is read with `GET /v1/sessions/{id}` and `GET /v1/calls/{call_id}` instead ([Sessions and calls](https://docs.sempera.org/sessions-and-calls.md)).

## Active calls across the workspace

`GET /v1/calls/active` lists the calls in progress on every agent the credential can read; `agent_id` narrows it to one. It answers `{"data": [...], "errors": null}`, each item `call_id` (the room), `agent_id`, `user_id` (the workspace id), `from` (masked), `to` (the masked line), `start_time`, `status` (always `IN_PROGRESS`) and `timestamp` (milliseconds since the epoch, as text). `objective`, `pathway_id` and `international` are always `null`: Sempera keeps none of them for a live call. When Sempera's live call service cannot be reached the list is empty and `errors` carries `{"error": "media_server_unreachable", "message": "..."}`. `GET /v1/calls/active/stream` sends exactly that answer as one `event: snapshot` frame.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.