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

# Recordings & transcripts

> Read a call's transcript and summary, and download its recording.

Everything about a single call is on [`GET /calls/{id}`](/api-reference/get-a-call-by-id) (scope `calls.view`).
To find call IDs, list calls with `GET /calls?campaignId=…`, or take `data.finalCall.id` from a
[lead result](/guides/receive-results).

<Note>`GET /calls` and `GET /calls/{id}` are part of the workspace API and need a scoped API key.</Note>

## Transcripts

```bash theme={null}
curl https://api.pineyard.ai/calls/00000000-0000-4000-8000-0000000000b1 \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
```

Relevant fields in the response:

| Field | Meaning |
| - | - |
| `transcript` | Array of turns, or `null` if there is no transcript (yet). |
| `transcriptLang` | Language of the transcript, when known. |
| `summary` | Short summary of the call, or `null`. |
| `extraction` | Values extracted from the call for the campaign's fields. |
| `hasRecording` | `true` when a recording is available. |
| `durationMs` | Call length in milliseconds. |

Each transcript turn looks like this:

```json theme={null}
{ "role": "agent", "text": "Hi Jordan, this is Ava from Acme. Is now a good time?", "startedAtMs": 1760437502000 }
```

* `role` is `agent`, `user` (the person called) or `system`.
* `startedAtMs`, when present, is the **Unix time in milliseconds** at which the turn started (not an offset from the
  start of the call). Subtract the call's `answeredAt` to get an offset.

### English translation

For a call in another language, `POST /calls/{id}/transcript-translation` returns an English version:

```json theme={null}
{ "lang": "hi", "alreadyEnglish": false, "turns": [ { "role": "agent", "text": "Hello, am I speaking with Jordan?" } ] }
```

The translation is stored, so later calls return it immediately and it also appears as `transcriptTranslation` on
`GET /calls/{id}`. A call with no transcript returns `400 no_transcript`. API keys need `calls.edit` for this
endpoint (see [stricter permissions](/concepts/scopes#stricter-permissions-for-keys)).

## Recordings

Download a recording from:

```text theme={null}
https://api.pineyard.ai/recordings/{callId}
```

This URL **redirects** (`302`) to a short-lived download link for the audio. Follow the redirect and download
straight away: the link it points to expires after a short time, but the `/recordings/{callId}` URL itself
never expires. Store the `/recordings/{callId}` URL or the call ID, not the link it redirects to.

```bash theme={null}
curl -L -o recording https://api.pineyard.ai/recordings/00000000-0000-4000-8000-0000000000b1
```

| Response | Meaning |
| - | - |
| `302` | Redirect to the audio. |
| `404 not_found` | No call with this ID. |
| `404 no_recording` | This call has no recording. |
| `502 provider_error` | The recording couldn't be fetched right now, often because it isn't ready yet. Retry later with back-off. |

<Warning>
  `/recordings/{callId}` does **not** require an API key. The call ID is long and random and works like a
  share link: anyone who has it can play the recording. Share call IDs only with people who may hear the call.
</Warning>

<Note>
  Use `/recordings/{callId}` rather than the `recordingUrl` field of `GET /calls/{id}`. `recordingUrl` is a
  temporary link that stops working once `recordingUrlExpires` has passed.
</Note>

## When transcripts and recordings become available

A call reaches its final status first; the transcript, summary, recording and extracted fields can arrive
**afterwards**. Analysis waits for the transcript and keeps retrying for several hours if it
is late.

* If `transcript` is `null` or `hasRecording` is `false` shortly after a call ended, poll `GET /calls/{id}` again
  later. Back off between attempts.
* A [lead result](/guides/receive-results) is created only after the call's analysis has finished, so by the time you
  receive it the transcript is normally available on `GET /calls/{data.finalCall.id}`.
* Calls that never connected have no transcript or recording.


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