Skip to main content

GET /calls/{callid}/recordings

List a call's recordings

Scoperecordings:read
Role permissionCall reports → allow recordings (OAuth only)
CostFree

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

NameTypeRequiredExampleDescription
callidstringyes1754489201.884213The 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.

FieldTypeDescription
[].uniqueIdstringIdentifies this leg. Pass it back to the per-leg endpoint to re-fetch just this one.
[].callIdstringThe 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.
[].urlstringPlays 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.
[].startTimestring (RFC 3339)When this leg started, RFC 3339 UTC.
[].durationSecondsintegerThe leg's full length including ringing.
[].talkTimeSecondsintegerOnly the connected portion — the closer match to the length of the audio.
[].fromstringThe leg's originating endpoint. On an internal leg this is an extension, not a phone number.
[].tostringThe 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

StatusMeaning
400invalid_request — a missing or malformed field, an unknown enum value, or an unknown field in the body. Nothing was charged.
401unauthenticated — no credential, or one that is invalid, revoked or expired. The WWW-Authenticate header names the scope the endpoint wanted.
403Two different failures share this status, and the type tells them apart:
404not_found — no such object, or it is not this account's. The two are deliberately indistinguishable.
500internal_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"

Try it in the playground →