GET /calls/{callid}/recordings
List a call's recordings
| Scope | recordings:read |
| Role permission | Call reports → allow recordings (OAuth only) |
| Cost | Free |
The most sensitive capability on this surface — a recording is the contents of a conversation, not metadata about it.
A call is not one recording. A call that rang a queue, was answered and then transferred has several legs, and each answered leg is recorded separately. Picking "the" recording of a transferred call is a judgement only you can make, so every leg's timings and endpoints are here.
200 with an empty array means the call exists but nothing was
recorded — recording is per-number and per-user opt-in. That is different
from 404, which means the call id isn't this account's. A client
polling for a recording still being written should treat [] as
"not yet" and retry; recordings usually appear within a minute of hangup.
One gate no credential opens: if the account has sensitive-content re-verification on, recordings are unavailable over the API entirely.
Path parameters
| Name | Type | Required | Example | Description |
|---|---|---|---|---|
callid | string | yes | 1754489201.884213 | The call id from call history, reports or a call webhook — a unix timestamp, a dot, and a sequence number. A malformed id is a 400 that names the expected shape, not a 404. |
Responses
200
Every recorded leg of the call. Empty if nothing was recorded.
| Field | Type | Description |
|---|---|---|
[].uniqueId | string | Identifies this leg. Pass it back to the per-leg endpoint to re-fetch just this one. |
[].callId | string | The switch's call id for the leg. On a transferred call it can differ from the id in the request path — the request id names the whole journey, this one names the leg. |
[].url | string | Plays the audio. A stable signed link on this platform, not the storage location: - Requires no Authorization header, so it can go straight into an <audio> element or a transcription service. - The account id is sealed inside the signature, so it cannot be edited to reach another account's recording. - It does not expire. Treat it as a secret — anyone holding it can play the conversation. |
[].startTime | string (RFC 3339) | When this leg started, RFC 3339 UTC. |
[].durationSeconds | integer | The leg's full length including ringing. |
[].talkTimeSeconds | integer | Only the connected portion — the closer match to the length of the audio. |
[].from | string | The leg's originating endpoint. On an internal leg this is an extension, not a phone number. |
[].to | string | The leg's destination endpoint. On an internal leg this is an extension. |
A transferred call — two recorded legs:
{
"data": [
{
"uniqueId": "1754489201.884213",
"callId": "1754489201.884213",
"url": "https://api.account.telebroad.com/recordings/play/9f2c…",
"startTime": "2026-08-11T13:20:01Z",
"durationSeconds": 96,
"talkTimeSeconds": 81,
"from": "13475550123",
"to": "204"
},
{
"uniqueId": "1754489288.884219",
"callId": "1754489288.884219",
"url": "https://api.account.telebroad.com/recordings/play/1ab4…",
"startTime": "2026-08-11T13:21:28Z",
"durationSeconds": 142,
"talkTimeSeconds": 139,
"from": "204",
"to": "301"
}
]
}
Call exists, nothing recorded:
{
"data": []
}
Errors
| Status | Meaning |
|---|---|
400 | invalid_request — a missing or malformed field, an unknown enum value, or an unknown field in the body. Nothing was charged. |
401 | unauthenticated — no credential, or one that is invalid, revoked or expired. The WWW-Authenticate header names the scope the endpoint wanted. |
403 | Two different failures share this status, and the type tells them apart: |
404 | not_found — no such object, or it is not this account's. The two are deliberately indistinguishable. |
500 | internal_error — something failed on our side. For a send, nothing was charged, guaranteed, which is what makes a retry safe. |
See Errors for the full catalog and what to do about each.
Example
curl -X GET 'https://api.account.telebroad.com/api/public/v1/calls/1754489201.884213/recordings' \
-H "Authorization: Bearer $TB_KEY"