# Get a finished chat conversation's transcript (/docs/api/voice-agents/chat-conversations/getChatConversationTranscript)

> 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/chat-conversations/{conversationId}/transcript`

Get a finished chat conversation's transcript

What the visitor read, oldest first. Tool calls are not part of a transcript: only what the visitor and the agent said is included.

`partial` is true when the stored transcript was unavailable and this is the agent's own retained history instead — which is trimmed from the front, so the beginning of a long conversation may be missing. A trimmed transcript is returned rather than none.

## 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 conversation's visitor-facing id, or the id it reports under in Call Logs. `conversationId` in the response echoes whichever was sent. |

## Responses

### 200 — The transcript.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `conversationId` | string | No | — |
| `agentId` | string | No | — |
| `widgetId` | string | No | — |
| `startedAt` | string (date-time) | No | — |
| `lastActivityAt` | string (date-time) | No | — |
| `endedAt` | string (date-time) | No | — |
| `disposition` | string | No | — |
| `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. |
| `partial` | boolean | No | — |

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