## Загрузить вложение

`POST /v1/feedback/attachments`

Загружает изображение и возвращает его идентификатор для последующей привязки к обращению или комментарию. Загрузка двухэтапная: сначала файл отправляется сюда, затем полученный `id` передаётся в поле `attachmentIds` при [создании обращения](./submit.md) или [добавлении комментария](./comments.md).

Файл передаётся как `multipart/form-data` в поле `file`. Принимаются PNG, JPEG, WebP и GIF. PNG, JPEG и WebP приводятся к WebP на стороне сервера, GIF пересобирается как GIF с сохранением анимации. Ограничения: до 10 МБ и до 24 миллионов пикселей на файл, до 5 вложений на одно сообщение и до 25 на обращение.

## Поля запроса (multipart/form-data)

| Поле | Тип | Обяз. | Описание |
|------|-----|:-----:|----------|
| `file` | file | да | Изображение PNG, JPEG, WebP или GIF, до 10 МБ |

## Примеры

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

```bash
curl -X POST https://vibecode.bitrix24.tech/v1/feedback/attachments \
  -H "X-Api-Key: YOUR_API_KEY" \
  -F "file=@screenshot.png"
```

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

```bash
curl -X POST https://vibecode.bitrix24.tech/v1/feedback/attachments \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -F "file=@screenshot.png"
```

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

```javascript
const form = new FormData()
form.append('file', fileInput.files[0])

const res = await fetch('https://vibecode.bitrix24.tech/v1/feedback/attachments', {
  method: 'POST',
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
  body: form,
})
const { data } = await res.json()
// data.id передайте в attachmentIds при создании обращения или комментария
```

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

```javascript
const form = new FormData()
form.append('file', fileInput.files[0])

const res = await fetch('https://vibecode.bitrix24.tech/v1/feedback/attachments', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
  body: form,
})
const { data } = await res.json()
```

## Поля ответа

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | Всегда `true` при успехе |
| `data.id` | string | UUID вложения. Передаётся в `attachmentIds` при создании обращения или комментария |
| `data.mime` | string | Тип после обработки: `image/webp` для PNG, JPEG и WebP, `image/gif` для GIF |
| `data.sizeBytes` | number | Размер обработанного файла в байтах |
| `data.width` | number | Ширина в пикселях |
| `data.height` | number | Высота в пикселях |
| `data.thumbnailUrl` | string | Путь к превью вложения |
| `data.originalName` | string | Имя исходного файла |
| `data.expiresAt` | string | Момент, после которого непривязанное вложение удаляется (ISO 8601) |

## Пример ответа

```json
{
  "success": true,
  "data": {
    "id": "1209c405-1f99-4240-95e5-d5cc0cd43560",
    "mime": "image/webp",
    "sizeBytes": 20480,
    "width": 1280,
    "height": 720,
    "thumbnailUrl": "/v1/feedback/_orphan/1209c405-1f99-4240-95e5-d5cc0cd43560/thumb",
    "originalName": "screenshot.png",
    "expiresAt": "2026-04-19T11:30:00.000Z"
  }
}
```

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

413 — файл больше 10 МБ:

```json
{
  "success": false,
  "error": {
    "code": "IMAGE_TOO_LARGE",
    "message": "File too large"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `NO_FILE` | В запрос не передан файл в поле `file` |
| 400 | `INVALID_MIME` | Формат не входит в PNG, JPEG, WebP, GIF |
| 400 | `IMAGE_TOO_MANY_PIXELS` | Больше 24 миллионов пикселей |
| 413 | `IMAGE_TOO_LARGE` | Файл больше 10 МБ |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 429 | `RATE_LIMITED` | Больше 5 загрузок в минуту с одного ключа |

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

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

**Вложение живёт час до привязки.** Загруженное вложение сначала не связано ни с одним обращением и удаляется после `expiresAt` (через час), если его `id` не передан в `attachmentIds` при создании обращения или комментария. После привязки вложение хранится вместе с обращением.

**Формат после обработки.** PNG, JPEG и WebP приводятся к WebP, поэтому их `mime` в ответе — `image/webp`. GIF пересобирается как GIF (`image/gif`) с сохранением анимации, до 30 кадров. Поля `sizeBytes`, `width` и `height` относятся к обработанному файлу.

## Операции с привязанным вложением

После привязки к обращению вложение доступно на скачивание и удаление по его `id` (поле `data.attachments[].id` в [Получить обращение](./get.md)). Эти операции работают с бинарными данными, поэтому у них нет JSON-тела и стандартного набора из 4 примеров.

### Скачать вложение

`GET /v1/feedback/:id/attachments/:attId/file`

Возвращает файл вложения. Доступно ключу, у которого есть доступ к обращению. `Content-Type` — тип вложения (`image/webp` или `image/gif`). Поддерживает `ETag` и `If-None-Match` (условный запрос отвечает `304 Not Modified`).

| Параметр | Тип | Обяз. | Описание |
|----------|-----|:-----:|----------|
| `id` (path) | string | да | UUID обращения |
| `attId` (path) | string | да | UUID вложения из `data.attachments[].id` |

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.tech/v1/feedback/a1b2c3d4-1111-2222-3333-444455556666/attachments/1209c405-1f99-4240-95e5-d5cc0cd43560/file" \
  -o attachment.webp
```

Если вложение не существует, недоступно ключу или не относится к указанному обращению — `404 NOT_FOUND`.

### Превью вложения

`GET /v1/feedback/:id/attachments/:attId/thumb`

Возвращает уменьшенное превью вложения. `Content-Type` — всегда `image/jpeg`. Параметры и правила доступа — как у скачивания файла.

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.tech/v1/feedback/a1b2c3d4-1111-2222-3333-444455556666/attachments/1209c405-1f99-4240-95e5-d5cc0cd43560/thumb" \
  -o thumb.jpg
```

### Удалить вложение

`DELETE /v1/feedback/:id/attachments/:attId`

Удаляет вложение. Доступно тому, кто его загрузил. При успехе возвращается `204 No Content` с пустым телом. Удалить нельзя, если другая сторона уже ответила после загрузки вложения.

| Параметр | Тип | Обяз. | Описание |
|----------|-----|:-----:|----------|
| `id` (path) | string | да | UUID обращения |
| `attId` (path) | string | да | UUID вложения |
| `reason` (body) | string | нет | Причина удаления, 3–500 символов |

```bash
curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.tech/v1/feedback/a1b2c3d4-1111-2222-3333-444455556666/attachments/1209c405-1f99-4240-95e5-d5cc0cd43560"
```

| HTTP | Код | Описание |
|------|-----|----------|
| 403 | `DELETE_NOT_ALLOWED` | Другая сторона уже ответила после загрузки вложения |
| 400 | `REASON_INVALID` | `reason` короче 3 или длиннее 500 символов |
| 404 | `NOT_FOUND` | Вложение не найдено, не принадлежит ключу или не относится к обращению |

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

- [Отправить обращение](/docs/feedback/submit)
- [Добавить комментарий](/docs/feedback/comments)
- [Обратная связь](/docs/feedback)
- [Ошибки](/docs/errors)
