For AI agents: markdown of this page — /docs-content-en/entities/task-comments/file-download.md documentation index — /llms.txt

Download a task comment attachment

GET /v1/tasks/:taskId/comments/:id/files/:fileId/download

Downloads a file attached to a task comment. The response is the file content as bytes rather than JSON, with the file name in a response header.

This endpoint exists because the file address is never exposed: it carries an authorization code, so requesting such an address from a third-party application returns the sign-in page with code 200 instead of the file. The endpoint adds the authorization itself. The task scope is enough — there is no need to extend the key's permissions to all of Drive, and the endpoint returns only a file from a comment the key can already read.

Parameters

Parameter Type Req. Description
taskId (path) number yes Task ID. Get it from GET /v1/tasks
id (path) number yes Comment ID. Get it from GET /v1/tasks/:taskId/comments or from the POST /v1/tasks/:taskId/comments response
fileId (path) number yes The attachments[].fileId value from the comment response — GET /v1/tasks/:taskId/comments/:id. The same full path is already in attachments[].downloadUrl — use it instead of assembling the address piece by piece

Examples

curl — personal key

Terminal
# Save under the original name from the response header
curl -OJ -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/tasks/3711/comments/9393/files/6687/download

# Set the file name explicitly
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/tasks/3711/comments/9393/files/6687/download \
  -o attachment.jpg

curl — OAuth app

Terminal
curl -OJ \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.com/v1/tasks/3711/comments/9393/files/6687/download

JavaScript — personal key

javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/tasks/3711/comments/9393/files/6687/download',
  { headers: { 'X-Api-Key': 'YOUR_API_KEY' } },
)

if (!res.ok) {
  const { error } = await res.json()
  throw new Error(`${error.code}: ${error.message}`)
}

const bytes = await res.arrayBuffer()
console.log('bytes received:', bytes.byteLength)

JavaScript — OAuth app

javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/tasks/3711/comments/9393/files/6687/download',
  {
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  },
)

const bytes = await res.arrayBuffer()

Response headers

On success the file content is returned with code 200. The response body is the file bytes rather than JSON, so the headers are described instead of response fields.

Header Example value Description
Content-Type image/jpeg Content type as Bitrix24 returned it
Content-Disposition attachment; filename="ava555.jpg" File name to save under
Content-Length 405559 Size in bytes when Bitrix24 reported it

Error response example

404 — the file does not belong to this comment:

JSON
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "File 6687 does not belong to comment 9395"
  }
}

Errors

HTTP Code Description
400 INVALID_PARAMS taskId, id or fileId is not a positive integer. No request reaches Bitrix24 in this case
401 TOKEN_MISSING The key has no configured Bitrix24 tokens
403 SCOPE_DENIED The key lacks the task scope
404 NOT_FOUND No comment with this id exists in the named task. The same response is returned when the task itself does not exist
404 NOT_FOUND The file exists but belongs to another comment, or it has no download address
422 BITRIX_ERROR Bitrix24 refused one of the calls behind this operation and named no more specific condition
429 RATE_LIMITED This code comes from two sources. The first is the operation's own limit, 30 requests per minute per key: take the effective value from the X-RateLimit-Limit header, and the remaining count and the reset time from X-RateLimit-Remaining and X-RateLimit-Reset — they arrive with every response of this operation, refusals included, and the refusal itself also carries Retry-After with the seconds until the window resets. The second is Bitrix24 rejecting a call under its own rate limit: that response carries the Retry-After: 2 header
503 BITRIX_TIMEOUT Bitrix24 accepted a call behind this operation but did not answer within the time limit. This operation is a read, so retrying is safe. Header Retry-After: 10
502 DOWNLOAD_FAILED The request for the file bytes returned a non-2xx status (including when Bitrix24 is temporarily unavailable for the file delivery itself), or Bitrix24 named an address outside the account domain — no request is sent to such an address
502 BITRIX_UNAVAILABLE Bitrix24 answered a REST call behind this operation — the comment lookup or the file details request — with a 5xx. The status is the same as for DOWNLOAD_FAILED; tell them apart by error.code. Both outcomes are temporary and safe to retry

The full list of common API errors — Errors.

Known specifics

  • The file must belong to the named comment. Otherwise you get a 404, even when the file exists and is reachable in another comment. The check is not pedantry: without it a numeric match on the identifier would hand over someone else's file.
  • A matching number means nothing. Chat comments and records in the comments block of the old card keep their identifiers in separate spaces, and those spaces overlap numerically. So the reliable source of fileId is the response for that same comment, not a number taken from somewhere else.
  • The path in downloadUrl arrives without a domain. The field points at this operation rather than at the file in Bitrix24. Join the path with the same API base address you called — the response does not repeat the domain.

See also