## Скачать вложение комментария задачи

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

Скачивает файл, приложенный к комментарию задачи. Ответ — содержимое файла байтами, а не JSON, с именем файла в заголовке ответа.

Этот эндпоинт нужен потому, что адрес файла наружу не отдаётся: в нём содержится код авторизации, поэтому запрос по такому адресу из сторонней программы возвращает страницу входа с кодом `200`, а не файл. Эндпоинт добавляет авторизацию сам. Скоупа `task` достаточно — расширять права ключа до всего Диска не требуется, и отдаёт он только файл того комментария, который этому ключу и так доступен на чтение.

## Параметры

| Параметр | Тип | Обяз. | Описание |
|----------|-----|:-----:|----------|
| `taskId` (path) | number | да | ID задачи. Получить: [`GET /v1/tasks`](/docs/entities/tasks) |
| `id` (path) | number | да | ID комментария. Получить: [`GET /v1/tasks/:taskId/comments`](./list.md) или ответ [`POST /v1/tasks/:taskId/comments`](./create.md) |
| `fileId` (path) | number | да | Значение `attachments[].fileId` из ответа по комментарию — [`GET /v1/tasks/:taskId/comments/:id`](./get.md). Тот же путь целиком лежит в `attachments[].downloadUrl` — берите его, чтобы не собирать адрес по частям |

## Примеры

### curl — личный ключ

```bash
# Сохранить с исходным именем из заголовка ответа
curl -OJ -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.tech/v1/tasks/3711/comments/9393/files/6687/download

# Указать имя файла явно
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.tech/v1/tasks/3711/comments/9393/files/6687/download \
  -o attachment.jpg
```

### curl — OAuth-приложение

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

### JavaScript — личный ключ

```javascript
const res = await fetch(
  'https://vibecode.bitrix24.tech/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.byteLength)
```

### JavaScript — OAuth-приложение

```javascript
const res = await fetch(
  'https://vibecode.bitrix24.tech/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()
```

## Заголовки ответа

При успехе приходит содержимое файла с кодом `200`. Тело ответа — байты файла, а не JSON, поэтому вместо полей ответа описаны заголовки.

| Заголовок | Пример значения | Описание |
|-----------|-----------------|----------|
| `Content-Type` | `image/jpeg` | Тип содержимого, как его отдал Битрикс24 |
| `Content-Disposition` | `attachment; filename="ava555.jpg"` | Имя файла для сохранения |
| `Content-Length` | `405559` | Размер в байтах, если Битрикс24 его сообщил |

## Пример ответа при ошибке

404 — файл не принадлежит этому комментарию:

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

## Ошибки

| HTTP | Код | Описание |
|------|-----|---------|
| 400 | `INVALID_PARAMS` | `taskId`, `id` или `fileId` не является положительным целым числом. Обращения к Битрикс24 при этом не происходит |
| 401 | `TOKEN_MISSING` | У ключа не настроены токены Битрикс24 |
| 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `task` |
| 404 | `NOT_FOUND` | Комментария с таким `id` нет в названной задаче. Тот же ответ приходит, когда нет самой задачи |
| 404 | `NOT_FOUND` | Файл существует, но принадлежит другому комментарию либо у него нет адреса для скачивания |
| 422 | `BITRIX_ERROR` | Битрикс24 отказал одному из вызовов, стоящих за этой операцией, и более точного условия не назвал |
| 429 | `RATE_LIMITED` | Код отдают два источника. Первый — собственный лимит операции, 30 запросов в минуту на ключ: действующее значение берите из заголовка `X-RateLimit-Limit`, остаток и время сброса — из `X-RateLimit-Remaining` и `X-RateLimit-Reset`, они приходят с каждым ответом операции, включая отказы, а сам отказ несёт ещё `Retry-After` с секундами до сброса окна. Второй — Битрикс24, отбивший вызов по лимиту частоты: приходит заголовок `Retry-After: 2` |
| 503 | `BITRIX_TIMEOUT` | Битрикс24 принял вызов, но не ответил в отведённое время. Операция читающая, поэтому повтор безопасен. Заголовок `Retry-After: 10` |
| 502 | `DOWNLOAD_FAILED` | Запрос за байтами вернулся не-2xx (в том числе когда Битрикс24 временно недоступен именно на выдаче файла), либо Битрикс24 назвал адрес за пределами домена аккаунта — по такому адресу запрос не уходит |
| 502 | `BITRIX_UNAVAILABLE` | Битрикс24 ответил 5xx на REST-вызов, стоящий за операцией, — чтение комментария или запрос сведений о файле. Статус тот же, что у `DOWNLOAD_FAILED`, различайте по `error.code`. Оба исхода временные и допускают повтор |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Известные особенности

- **Файл обязан принадлежать названному комментарию.** Иначе приходит `404`, даже когда файл существует и доступен в другом комментарии. Проверка нужна не для строгости: без неё совпадение идентификатора по числу отдало бы чужой файл.
- **Совпадение номера ничего не значит.** У комментариев чата и у записей блока комментариев старой карточки идентификаторы живут в разных пространствах и пересекаются по числу. Поэтому надёжный источник `fileId` — ответ по тому же комментарию, а не число, взятое из другого места.
- **Путь в `downloadUrl` приходит без домена.** Поле указывает на эту операцию, а не на файл в Битрикс24. Склейте путь с тем же базовым адресом API, к которому обращались, — домен в ответе не дублируется.

## Смотрите также

- [Получить комментарий](./get.md)
- [Список комментариев](./list.md)
- [Поля комментария](./fields.md)
- [Комментарии задач](/docs/entities/task-comments)
- [Задачи](/docs/entities/tasks)
