curl https://api.tracklysms.com/api/v1/voice/calls/665f1e2a9c4b1a0012ab34cd/recording/files/665f1e2a9c4b1a0012abd001 \
-H "X-Api-Key: trk_your_api_key_here" \
--output recording.wav
Voice Calls (v1)
Download a Recording File
Stream the raw audio bytes of a single recording file.
GET
/
v1
/
voice
/
calls
/
{callId}
/
recording
/
files
/
{fileId}
curl https://api.tracklysms.com/api/v1/voice/calls/665f1e2a9c4b1a0012ab34cd/recording/files/665f1e2a9c4b1a0012abd001 \
-H "X-Api-Key: trk_your_api_key_here" \
--output recording.wav
Streams the raw audio for one recording file. The
For a conditional range request, send the returned
fileId is validated against the call’s known recording files before the stream begins. Unlike the other voice endpoints, this route does not return JSON — the response body is the audio itself.
Requires the voice_calls.read scope and the Voice Calls product entitlement.
Path Parameters
string
required
The id of the call the recording belongs to.
string
required
The recording file id, as returned by List Recordings.
Response
The response body is the raw audio stream, not JSON. Archived recordings useaudio/wav; other recordings retain their audio content type, defaulting to audio/wav. Write the response straight to a file (for example with curl’s --output).
Send HEAD to the same URL to check metadata without downloading audio or incurring a retrieval charge. It requires the same authentication and scope as GET.
Playback and partial downloads
Archived recordings return one byte range per response. UseRange: bytes=0-65535, bytes=65536-, or bytes=-65536 to request a bounded segment, the remaining bytes, or the final bytes. A successful range request returns 206 Partial Content.
For a valid list such as Range: bytes=0-50,100-150, the response contains the first satisfiable range in request order. Well-formed ranges outside the recording are skipped. The entire list is validated before delivery; a malformed or reversed member rejects the request even if an earlier member is satisfiable. No multipart body is returned. The header may contain at most 1,024 characters and 16 comma-delimited slots, including empty slots. Empty slots are ignored; a list containing only empty slots is invalid.
| Header | Meaning |
|---|---|
Content-Length | Bytes in this response; on HEAD, the full recording size. |
Content-Range | Selected range and full size for a 206 response. |
Accept-Ranges: bytes | This recording supports byte ranges. |
ETag | Opaque recording version; preserve the entire value, including quotes. |
X-Content-SHA256 | SHA256 of the complete recording, including on a partial response; do not compare it with the hash of a downloaded range. |
Cache-Control: no-store | Do not retain the response in an HTTP cache. |
ETag in If-Range. Only an exact match uses the range; a missing match, weak validator, or date returns the full recording with 200. Unsupported range units also return the full recording. Invalid or oversized range lists, or lists with no satisfiable range, return 416 with Content-Range: bytes */<full size>.
Recordings that are not yet archived return the full audio with 200 and do not advertise byte-range support. Check Accept-Ranges before relying on seeking. HEAD ignores range headers and returns no audio body.
Retrieval charges
The offered retrieval rate is $0.50 per decimal GB served after the first 30 completed days, only when included in your account’s accepted calling terms. One GB is 1,000,000,000 bytes; charges are prorated to bytes, with no whole-GB minimum. Check Organization → Rates for your accepted price. Publishing this rate does not change existing terms. Playback and downloads during the first 30 days are included. Recording still includes 90-day retention; storing a recording and retrieving it are separate services. The retrieval age starts when the recording completes, not when you first play it. Each separateGET, including a repeated download or playback range, can incur a charge for bytes served. Interrupted transfers are charged only for the bytes Trackly handed to its HTTP server, not the requested file size. This measures delivery from Trackly, not confirmed playback or receipt on your device. After a server failure, only durably retained progress is chargeable; uncertain bytes are excluded. Metadata checks, failed authorization, and Trackly’s storage maintenance reads do not incur retrieval charges.
Examples
curl https://api.tracklysms.com/api/v1/voice/calls/665f1e2a9c4b1a0012ab34cd/recording/files/665f1e2a9c4b1a0012abd001 \
-H "X-Api-Key: trk_your_api_key_here" \
--output recording.wav
Error Codes
Admission and preparation failures return an error before any audio is served.| Status | Code | Meaning |
|---|---|---|
| 402 | voice_payment_required | An account payment hold blocks billable retrieval. Resolve the hold before retrying. |
| 403 | voice_not_entitled | Voice calling is not enabled for your account. |
| 404 | call_not_found | No call with that id exists on your account. |
| 404 | file_not_found | No recording file with that id belongs to the call. |
| 409 | call_not_ready | The call has not yet been accepted by the provider. |
| 416 | recording_range_not_satisfiable | The archived recording cannot satisfy the requested byte range. |
| 502 | provider_error | The upstream telephony provider rejected the request. |
| 502 | recording_archive_unavailable | The recording archive could not be read or verified. No unverified audio is returned; contact support if this persists. |
| 503 | recording_archive_busy | Download capacity is temporarily busy. Retry shortly. |
| 503 | voice_billing_unavailable | Billing authority could not be established. Retry later or contact support if this persists. |
| 503 | recording_retrieval_indexes_unavailable | The retrieval billing service is not ready. Contact support. |