# Get a call's transcript (/docs/api/voice-agents/calls/getCallTranscript)

> For the complete documentation index, see [llms.txt](https://docs.tandemcx.ai/llms.txt). Any page on this site can be fetched as Markdown by appending `.md` to its URL.

`GET /v1/agent-media/calls/{conversationId}/transcript`

Get a call's transcript

The call's turns, oldest first. Returns 404 once the transcript has expired or been erased, even while the call record itself is still readable.

## Request

**Base URL:** `https://api.tandemcx.ai`

**Authentication:** `Authorization: Bearer <token>` — A Tandem bearer token. Requests are scoped to the organization the token belongs to; no organization header is required.

### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `conversationId` | string | Yes | The call's conversation ID. |

## Responses

### 200 — The transcript.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `transcript` | array of object | No | — |
| `transcript[].role` | enum: `user` \| `assistant` \| `system` \| `tool` | No | `system` is a line the platform wrote into a chat conversation, such as "Transferred to Billing" after an agent transfer. Nobody said it. A call transcript never carries one. `tool` is a tool call, with `text` empty, and appears on a call's transcript and the live stream, never on a finished chat's transcript. |
| `transcript[].text` | string | No | — |
| `transcript[].tool` | object | No | One tool call. Present exactly when `role` is `tool`. |
| `transcript[].tool.toolUseId` | string | Yes | — |
| `transcript[].tool.name` | string | Yes | — |
| `transcript[].tool.kind` | string | No | `builtin`, `integration`, `workflow`, `mcp`, or `skill`. Absent when the platform did not time the call. |
| `transcript[].tool.status` | enum: `ok` \| `error` \| `running` \| `unknown` | Yes | How the call turned out. `ok` means the tool answered, whatever the answer was: an integration whose endpoint replied `404` is `ok`, and `httpStatus` carries the `404`. `unknown` is a call the conversation ended before it answered. |
| `transcript[].tool.durationMs` | integer | No | — |
| `transcript[].tool.args` | unknown | No | The arguments the agent sent. |
| `transcript[].tool.errorText` | string | No | The failure reason, only when `status` is `error`. |
| `transcript[].tool.httpStatus` | integer | No | The HTTP status an integration tool's endpoint answered with. Present for every caller. A network failure, such as a DNS error or a refused connection, reads `502`. If the integration's own request timeout fires first, it reads `408`. Absent when the call got no answer, such as the tool's time limit firing first, and for tools that are not integrations. |
| `transcript[].tool.detail` | object | No | What the integration was sent, what it answered, and what the agent got back. Present only for a caller who passes the organization-admin check; it is removed server-side for anyone else, not hidden by the client. It can hold your endpoint's customer data. It is kept for 90 days, and on a call or chat it is deleted with the transcript. A tool that is not an integration has no `request` or `response`, only `agentSaw`. Calls recorded before this was captured have no `request` or `response` either. |
| `transcript[].tool.detail.request` | object | No | The request as the platform built it. Credentials stored on the integration are added afterward and are not shown. |
| `transcript[].tool.detail.response` | object | No | The response as the integrations service returned it, with the integration's secret values removed. Not the bytes on the wire. |
| `transcript[].tool.detail.agentSaw` | unknown | No | The value the tool returned to the agent, after any response extraction. |
| `transcript[].at` | string (date-time) | No | When this turn was recorded. Present on the live transcript stream, where each turn is stamped as it arrives; absent on a finished call's transcript, and absent on any turn recorded before the field existed. Show a time when there is one rather than assuming one — the turn is otherwise unchanged. On a voice call this is when the platform received the turn from the agent, which trails what the caller said by the model round trip. On a chat it is when the turn was recorded, so the visitor's message and the reply to it carry the times they actually landed. |
| `truncated` | boolean | No | True when the call exceeded the stored-transcript size cap and later turns were dropped. |
| `supervised` | array of object | No | What the caller and the supervisor said after a supervisor took the call over, oldest first. These come after the last of `transcript`, since the agent had left. Absent when nobody took the call over. |
| `supervised[].id` | string | Yes | — |
| `supervised[].speaker` | enum: `caller` \| `supervisor` | Yes | — |
| `supervised[].text` | string | Yes | — |
| `supervised[].at` | string (date-time) | Yes | — |

### 400 — The request was malformed. `error` names the reason, such as `invalid_agentId`, `invalid_version`, `invalid_slot`, or `invalid_prompt`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string | No | A stable machine-readable code. |
| `message` | string | No | A human-readable explanation, safe to show to an end user. Present on errors an operator can act on; browser clients display this field in preference to a generic fallback. |
| `limit` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the bound itself. |
| `length` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the measured size of the rejected value. |
| `reason` | string | No | Present on some errors (e.g. `invalid_avatar_image`) that have more than one cause: which one applied. |

### 401 — Missing, malformed, or expired bearer token.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string | No | A stable machine-readable code. |
| `message` | string | No | A human-readable explanation, safe to show to an end user. Present on errors an operator can act on; browser clients display this field in preference to a generic fallback. |
| `limit` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the bound itself. |
| `length` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the measured size of the rejected value. |
| `reason` | string | No | Present on some errors (e.g. `invalid_avatar_image`) that have more than one cause: which one applied. |

### 404 — The resource does not exist.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string | No | A stable machine-readable code. |
| `message` | string | No | A human-readable explanation, safe to show to an end user. Present on errors an operator can act on; browser clients display this field in preference to a generic fallback. |
| `limit` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the bound itself. |
| `length` | integer | No | Present on some errors (e.g. `prompt_too_long`) that reject a value against a fixed bound: the measured size of the rejected value. |
| `reason` | string | No | Present on some errors (e.g. `invalid_avatar_image`) that have more than one cause: which one applied. |
