Get transcripts and recordings
Track a call by its ID, then read its transcript and summary and download its recording.
All of these routes need an API key with read permission. The JavaScript samples use top-level await, so save them as .mjs files and run them with Node 18 or later.
- Wait for the call to finish
POST /v1/callsreturns acallId. Pass it toGET /v1/calls/{id}untilstatusiscompletedorfailed.A call can wait overnight for calling hours, so don't treat a long
queuedas a failure. This loop checks every 30 seconds for up to an hour. Polling counts toward your rate limits.const API = 'https://backend.synthesys.app/api/v1'; const headers = { SYNTH_API_KEY: 'YOUR_API_KEY' }; const callId = '9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d'; async function waitForCall() { for (let check = 0; check < 120; check += 1) { const response = await fetch(`${API}/calls/${callId}`, { headers }); const { data: call } = await response.json(); if (['completed', 'failed'].includes(call.status)) return call; await new Promise((resolve) => setTimeout(resolve, 30_000)); } throw new Error('The call has not finished yet'); } const call = await waitForCall(); console.log(call.status, call.failure_code, call.failure_message);A failed call says why. If
provider_call_idisnull, the call never went out, so there is no log or recording to read. This example is trimmed.{ "success": true, "data": { "id": "7c6d5e4f-3a2b-4c1d-8e0f-9a8b7c6d5e4f", "status": "failed", "failure_code": "outside_calling_hours", "failure_message": "The call could not be placed within the recipient's calling hours.", "provider_call_id": null, "contact_phone": "+12025550123", "duration_seconds": null, "created_at": "2026-10-31T14:02:12.103Z", "completed_at": "2026-11-02T01:02:12.103Z" } } - Find the call log
A call that ran has a call log, with its own
call_id. ItsdirectCallIdmatches yourcallId, so filter on that field to find it.curl -G "https://backend.synthesys.app/api/v1/call-logs" \ -H "SYNTH_API_KEY: YOUR_API_KEY" \ --data-urlencode "directCallId=9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"Logs come back newest first. If an agent has more than 100 calls in the range, request further pages with
page. The log can appear shortly after the call finishes, so check again if there's no match. This example is trimmed.{ "success": true, "data": [ { "call_id": "5b9e2d70-1c34-4a8f-9e62-7d1a0c3f4b25", "provider_call_id": "2e4f6a8c-1b3d-4f5a-9c7e-0d2b4f6a8c1e", "directCallId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d", "contactPhoneNumber": "+12025550123", "agent_id": "3f0c1a52-7b7e-4c7a-9a55-1f2d3e4c5b6a", "agentName": "Sales outreach", "status": "ended", "ended_reason": "customer-ended-call", "duration": 142, "start_time": "2026-10-31T14:02:11+00:00", "end_time": "2026-10-31T14:04:33+00:00", "summary": "Jane asked to upgrade her plan next month.", "hasTranscript": true, "created_at": "2026-10-31T14:02:09+00:00", "updated_at": "2026-10-31T14:04:40+00:00" } ], "pagination": { "total": 1, "page": 1, "limit": 100, "totalPages": 1 } } - Get the transcript and summary
Pass the
call_idtoGET /v1/call-logs/:id. The final transcript can arrive shortly after the status changes. IfhasTranscriptisfalse, check again a minute later.curl "https://backend.synthesys.app/api/v1/call-logs/5b9e2d70-1c34-4a8f-9e62-7d1a0c3f4b25" \ -H "SYNTH_API_KEY: YOUR_API_KEY"The response has the log, the transcript as a list of turns, and any timed messages. This example is trimmed.
{ "success": true, "data": { "callLog": { "call_id": "5b9e2d70-1c34-4a8f-9e62-7d1a0c3f4b25", "directCallId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d", "status": "ended", "ended_reason": "customer-ended-call", "duration": 142, "summary": "Jane asked to upgrade her plan next month.", "outcome_summary": "Jane asked to upgrade her plan next month.", "key_points": null, "hasTranscript": true }, "transcriptText": [ { "role": "assistant", "message": "Hi Jane, I am calling about your growth plan." }, { "role": "user", "message": "Thanks. I would like to upgrade next month." } ], "messages": [] } } - Find the recording
Pass the same
call_idascall_log_idtoGET /v1/recordings. A recording can be downloaded when itsstatusisready. The list is empty when the call has no recording yet.curl "https://backend.synthesys.app/api/v1/recordings?call_log_id=5b9e2d70-1c34-4a8f-9e62-7d1a0c3f4b25" \ -H "SYNTH_API_KEY: YOUR_API_KEY"This example is trimmed.
{ "success": true, "data": [ { "id": "e41f7c09-6a2b-4d53-b8c1-90d2f3a4e5b6", "call_log_id": "5b9e2d70-1c34-4a8f-9e62-7d1a0c3f4b25", "status": "ready", "duration": 142, "format": "mp3", "customer_phone": "+12025550123", "call_status": "ended", "call_ended_reason": "customer-ended-call", "recording_url": null, "stereo_recording_url": null, "created_at": "2026-10-31T14:04:45+00:00" } ], "pagination": { "total": 1, "page": 1, "limit": 50, "totalPages": 1 } }recording_urlandstereo_recording_urlare alwaysnull. The next step gets you a link. - Download the audio
GET /v1/recordings/:id/download-urlreturns a signed link. It works without an API key untilexpiresAt, which is one hour away. Download the file straight away, and request a new link if it expires.url=$(curl -s "https://backend.synthesys.app/api/v1/recordings/e41f7c09-6a2b-4d53-b8c1-90d2f3a4e5b6/download-url" \ -H "SYNTH_API_KEY: YOUR_API_KEY" | jq -r '.data.url') curl -o recording.mp3 "$url"{ "success": true, "data": { "url": "https://example.com/signed/recording.mp3?token=SIGNED_TOKEN", "type": "mono", "expiresInSeconds": 3600, "expiresAt": "2026-10-31T15:10:00.000Z", "disposition": "attachment" } }A recording that isn't ready returns
409with the codeRECORDING_NOT_READY. Add?type=stereofor separate channels, and?disposition=inlineto play it in place.
Call fields
Fields used on this page
idstringcallId.statusstringqueued, dialing, in_progress, completed or failed.failure_codestring | nullfailure_messagestring | nullfailure_code.provider_call_idstring | nullduration_secondsinteger | nullCall log fields
Fields used on this page
call_idstringcall.id.directCallIdstringcallId this log belongs to. Left out for calls not placed with POST /v1/calls.contactPhoneNumberstringprovider_call_idstringagent_idstringnull.agentNamestringstatusstringended and failed mean it has finished.ended_reasonstringcustomer-ended-call, or null.durationintegernull.start_timestringnull if unknown.end_timestringnull.summarystringnull.outcome_summarystringsummary.key_pointsarraynull.hasTranscriptbooleanTranscript fields
transcriptText is the simplest way to read a call. Each item has a role of user or assistant, and a message.
messages holds per-turn timing, but it's often empty. Each item has message_order, role, message_text, timestamp, end_timestamp, duration_ms and seconds_from_start.
Errors
GET /v1/calls/:idreturns404withCall not foundwhen the call isn't in your account.GET /v1/call-logsreturns400whenpage,limit,agent_idor a date is invalid.GET /v1/call-logs/:idreturns404withCall log not foundwhen the log isn't in your account.GET /v1/recordingsreturns400whencall_log_idisn't a UUID. It returns an emptydatalist when the call has no recording yet.GET /v1/recordings/:id/download-urlreturns409 RECORDING_NOT_READYwhen there's no audio to download yet.