For AI agents: markdown of this page — /docs-content-en/entities/activities/file-download.md documentation index — /llms.txt
Download an activity file
GET /v1/activities/:activityId/files/:fileId/download
Downloads a file attached to a CRM activity, including a call recording. The response is a binary stream with a Content-Disposition header.
This endpoint exists because an activity file is not a Disk file. GET /v1/activities/:id returns each file as { id, url }, where the id lives in a separate identifier space that overlaps Disk object ids. Passing such an id to Disk file download is not safe: it may well return a different file. And the address in the url field arrives with an empty authorization parameter, so requesting it returns the sign-in page with code 200 — not a file. This endpoint adds the authorization itself and returns the content.
Parameters
| Parameter | In | Type | Req. | Description |
|---|---|---|---|---|
activityId |
path | number | yes | Activity ID. Get it from GET /v1/activities |
fileId |
path | number | yes | File ID from the activity files array. Get it from GET /v1/activities/:id with files included in select |
The request body is empty.
Examples
curl — personal key
# Save under the original name from the Content-Disposition header
curl -OJ -H "X-Api-Key: YOUR_API_KEY" \
https://vibecode.bitrix24.com/v1/activities/4257/files/5387/download
# Set the file name explicitly
curl -H "X-Api-Key: YOUR_API_KEY" \
https://vibecode.bitrix24.com/v1/activities/4257/files/5387/download \
-o call-record.mp3
curl — OAuth application
curl -OJ \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
https://vibecode.bitrix24.com/v1/activities/4257/files/5387/download
JavaScript — personal key
const res = await fetch(
'https://vibecode.bitrix24.com/v1/activities/4257/files/5387/download',
{ headers: { 'X-Api-Key': 'YOUR_API_KEY' } },
)
if (!res.ok) {
const { error } = await res.json()
throw new Error(`${error.code}: ${error.message}`)
}
const audio = await res.arrayBuffer()
console.log('bytes received:', audio.byteLength)
JavaScript — OAuth application
const res = await fetch(
'https://vibecode.bitrix24.com/v1/activities/4257/files/5387/download',
{
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
},
)
const audio = await res.arrayBuffer()
Response headers
On success the binary file content is returned (HTTP 200). There is no ## Response fields section — the response body is not JSON.
| Header | Example value | Description |
|---|---|---|
Content-Type |
audio/mpeg |
Content type exactly as Bitrix24 returned it |
Content-Disposition |
attachment; filename="call-record.mp3" |
File name to save under |
Content-Length |
22509 |
Size in bytes when Bitrix24 reported it |
Error response example
404 — the file does not belong to this activity:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "File 999999 does not belong to activity 4257"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
activityId or fileId is not a positive integer |
| 401 | TOKEN_MISSING |
The key has no configured Bitrix24 tokens |
| 403 | SCOPE_DENIED |
The key lacks the crm scope |
| 404 | NOT_FOUND |
The activity does not exist, the file does not belong to it, or the file has no download address |
| 502 | DOWNLOAD_FAILED |
Bitrix24 named an address outside the account domain (no request is sent to such an address), or did not return the file. This includes answering with a page instead of the content, which means the key could not be authorized for that file |
The full list of common API errors — Errors.
Known specifics
- The file must belong to the named activity. Otherwise
404, even when the file exists. The check is not pedantry: Bitrix24 answers a foreign file with200and a sign-in page, so without it you would receive HTML posing as the file. - Permissions are not bypassed. Reading the activity IS the access check: a key without access to the activity gets a refusal. Bitrix24 additionally verifies the user's access to the activity on its side.
- The address is never returned. The download address contains an authorization code, so the endpoint returns bytes only.
- Files are not always present in the activity response. In the activity list the
filesfield is returned only when named inselect. For a single activity it arrives with no extra conditions.