Download Audio
Download a recording’s audio file to keep your own copy of your calls.
https://api.identitycall.ai/api/v1/public/recordings/:id/audioReturns the audio file exactly as it was stored (WAV, MP3, M4A, OGG, ...).
The response body is the file itself, not JSON. Content-Type names the format, Content-Length the size in bytes, and Content-Disposition carries the original file name.
Audio is kept for your data retention period (set for the account, and optionally per project). When it runs out, the audio is deleted and this endpoint answers 410, while the recording, transcript and analysis stay. Download what you need before then, or set retention to Indefinite.
Path Parameters
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | - | Recording public_id (UUID), or the legacy numeric id |
Headers
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
Range | string | No | - | Byte range to fetch, e.g. bytes=1048576- to resume a download after the first MB. Answered with 206 Partial Content, at most 8 MB per response. |
Request
cURL
# -OJ saves the file under its original name
curl -OJ "https://api.identitycall.ai/api/v1/public/recordings/018f3a00-0000-7000-8000-0000000000a1/audio" \
-H "Authorization: Bearer $IDENTITYCALL_API_KEY"Response
HTTP/1.1 200 OK
Content-Type: audio/wav
Content-Length: 2654252
Content-Disposition: inline; filename="call.wav"; filename*=UTF-8''call.wav
Accept-Ranges: bytes
<binary audio data>With Range: bytes=1048576- (everything after the first MB):
HTTP/1.1 206 Partial Content
Content-Type: audio/wav
Content-Range: bytes 1048576-2654251/2654252When the audio was deleted by the retention policy:
{
"error": "Audio deleted",
"reason": "retention",
"deleted_at": "2026-09-14T03:00:12Z"
}Archive every call
Walk the recordings list and download each file once. Files are named by public_id, so a rerun only fetches calls that are new since the last run, and a half-finished download never counts as done.
import os
import re
import requests
API_KEY = os.environ["IDENTITYCALL_API_KEY"]
BASE_URL = "https://api.identitycall.ai/api/v1/public"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
ARCHIVE_DIR = "call-archive"
os.makedirs(ARCHIVE_DIR, exist_ok=True)
done = {name.split(".")[0] for name in os.listdir(ARCHIVE_DIR) if not name.endswith(".part")}
page = 1
while True:
listing = requests.get(f"{BASE_URL}/recordings", headers=HEADERS,
params={"page": page, "per_page": 100})
listing.raise_for_status()
body = listing.json()
for recording in body["data"]:
public_id = recording["public_id"]
if public_id in done:
continue
with requests.get(f"{BASE_URL}/recordings/{public_id}/audio",
headers=HEADERS, stream=True) as response:
if response.status_code in (404, 410): # no audio, or removed by retention
continue
response.raise_for_status()
original = re.search(r'filename="([^"]+)"', response.headers["Content-Disposition"]).group(1)
path = os.path.join(ARCHIVE_DIR, public_id + os.path.splitext(original)[1])
with open(path + ".part", "wb") as f:
for chunk in response.iter_content(chunk_size=1 << 20):
f.write(chunk)
os.replace(path + ".part", path)
if page >= body["meta"]["total_pages"]:
break
page += 1An internal call recorded on both lines appears in the list once (see List Recordings), so the archive holds one file per conversation.
Errors
| Status | Error | Description |
|---|---|---|
| 403 | “Read permission required” | The API key has no read permission |
| 404 | “Resource not found” | Recording doesn’t exist, or is outside the key’s project |
| 404 | “No audio attached” | The recording has no audio file |
| 410 | “Audio deleted” | The audio was deleted by the retention policy |
| 416 | The Range starts beyond the end of the file |