Skip to content
RelationsAI
Guides

Retrieving recordings and transcripts

Available

After a call settles you can read its transcript and get a link to its recording. This guide covers when the artifacts are available, the shape of a transcript and how to download recordings through short-lived links.

Before you begin

Artifact scopes are separate from calls:read on purpose: a key that only needs call outcomes does not have to see what was said. The requests below use the documented example call id; use the id of your call. Any test call to +12025550100 produces both artifacts.

When artifacts are ready

Artifacts are produced after the call ends. Each call reports their state in artifacts:

JSONJSON
"artifacts": { "transcript": { "state": "ready" }, "recording": { "state": "ready" }, "analysis": { "state": "ready" } }
StateMeaningWhat to do
pendingNot ready yetWait for call.settled, or read the call again later
readyAvailableRead it from its endpoint
absentThere is none for this callNothing to fetch (for example a call nobody answered)
failedIt could not be producedNothing to fetch; contact support with the call id if it keeps happening

The simplest rule: fetch artifacts after call.settled (or once settled is true when polling). In live mode they are usually ready within a minute of the call ending, sometimes several minutes later. In test mode they are ready about 30 seconds after the call is created. Transcripts are not available while a call is in progress (capabilities.live_transcript is false).

Which test-mode calls have which artifacts:

toTranscriptRecording
+12025550100, +12025550105, +12025550106readyready
+12025550104 (answered, nobody spoke)absentready
+12025550101, +12025550102, +12025550103 (not connected)absentabsent

Transcript

GET/calls/{call_id}/transcript returns the conversation turn by turn, verbatim. Nothing is masked: it is what was said.

curl -X GET https://voice-api.relationsai.com/v1/calls/call_6Vb3Nm8Qw2Er5Ty9Ui4Op7/transcript \ -H "Authorization: Bearer <token>"
Complete runnable example

Print a call's transcript, turn by turn.

The same steps as a complete script, with error handling, tested against test mode on every docs build. Each script reads your test key from an environment variable named in its first lines.

The response (200):

JSONJSON
{ "object": "call_transcript", "livemode": true, "call_id": "call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1", "state": "ready", "simulated": false, "turns": [ { "index": 0, "speaker": "agent", "text": "Hello, this is an AI assistant calling from Acme Lending. Am I speaking with Asha?", "start_ms": 400, "end_ms": 4900 }, { "index": 1, "speaker": "caller", "text": "Yes, speaking.", "start_ms": 5600, "end_ms": 6500 } ] }
  • speaker is agent or caller (the person called). Open enum.
  • index orders the turns from 0. start_ms and end_ms are milliseconds from the start of the call, or null when not known.
  • turns is empty unless state is ready. A transcript that is still pending is answered with 200 and state: "pending", not an error.
  • simulated is true for test-mode fixture transcripts. Do not import them into production systems.

Recording

Preview The recording endpoints are in preview and may change.

GET/calls/{call_id}/recording returns the recording's state and, when it is ready, a short-lived HTTPS link to the audio.

First read the recording to get a fresh link:

curl -X GET https://voice-api.relationsai.com/v1/calls/call_6Vb3Nm8Qw2Er5Ty9Ui4Op7/recording \ -H "Authorization: Bearer <token>"

Then, while state is ready and before expires_at, download the audio from its url. The link needs no API key (see the response below for its shape):

curl https://voice-api.relationsai.com/v1/recordings/rec_tok_Y2FsbF82VmIzTm04UXcyRXI1VHk5VWk0T3A3 \ -o call-recording.audio
Complete runnable example

Download a call's recording to a local file.

The same steps as a complete script, with error handling, tested against test mode on every docs build. Each script reads your test key from an environment variable named in its first lines.

The response (200):

JSONJSON
{ "object": "call_recording", "livemode": true, "call_id": "call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1", "state": "ready", "simulated": false, "url": "https://voice-api.relationsai.com/v1/recordings/rec_tok_Y2FsbF8ySGQ4S3M0THE3TXczTng5UHo1UmMx", "expires_at": "2026-10-21T10:00:00.000Z", "content_type": null }

How the link works:

  • url is valid for about 15 minutes, until expires_at. After that it answers media_link_expired (410); call the recording endpoint again for a fresh link.
  • The link needs no API key: the token in the path is the credential. It is tied to the key that obtained it: it stops working (404) as soon as that key is revoked or expires, loses recordings:read, or its creator leaves the workspace, even before expires_at.
  • Until then it works for anyone who has it. Treat it like a password. Do not log it, store it, put it in a URL you share, or send it to a browser you do not control. Download the audio on your server and serve it from your own storage if people need to play it.
  • content_type is audio/wav for test-mode audio and is usually null in live mode, where the format is known only when you download it: the download's Content-Type header is authoritative.
  • The download supports Range requests, so a player can seek. A range that cannot be served is answered with the whole file (200).
  • In test mode the audio is a short synthetic file and simulated is true.

If you need to keep recordings, copy them into your own storage promptly and apply your own retention rules.

Handling call content

Transcripts and recordings are personal data of the person you called: their voice and what they said. RelationsAI returns them to your workspace in full. Store and share them according to your own data-protection obligations and your agreements with the people you call: restrict who can read them, keep them only as long as you need, and do not copy them into logs, analytics tools or tickets. See Security and data handling.

What can go wrong

  • state: "pending": The call has not settled yet. Fix: Wait for call.settled and read again.
  • state: "absent": The call never connected, or nobody spoke (transcript). Fix: Nothing to fetch; check outcome on the call.
  • media_link_expired (410) on download: The link passed expires_at. Fix: Get a fresh link and download straight away.
  • insufficient_scope (403): The key lacks transcripts:read or recordings:read. Fix: Ask an admin for a key with that scope.
  • resource_not_found (404): The call id is from the other mode or another workspace. Fix: Use the key that created the call.

Next steps

Working with analysis results.