## Зарезервировать загрузку файла на Диск

`POST /v1/disk/uploads/reserve`

Регистрирует будущую загрузку файла на Диск Битрикс24 — первый шаг записи, содержимое файла передаётся следующим вызовом по идентификатору операции.

Тело плоское, без обёртки `fields`.

## Поля запроса (body)

| Поле | Тип | Обяз. | Описание |
|------|-----|:-----:|----------|
| `reserveRequestId` | string | да | Ваш идентификатор запроса резерва, от 1 до 512 символов. Повтор с тем же значением и тем же телом возвращает уже созданную операцию |
| `intent` | array | да | Намерение загрузки — массив ровно из восьми элементов в порядке строк ниже. Лишний, пропущенный или переставленный элемент даёт `400 INVALID_PARAMS` |
| `intent[0]` | number | да | Версия формата, всегда `1` |
| `intent[1]` | string | да | Режим: `create` — новый файл в папке, `version` — новая версия существующего файла |
| `intent[2]` | string | да | При `create` — ID папки, в которую ложится файл. Список: [`GET /v1/folders`](/docs/entities/folders/list), корневая папка хранилища — поле `rootFolderId` в [`GET /v1/storages/:id`](/docs/entities/storages/get). При `version` — ID файла `objectId` из [`POST /v1/disk/search`](/docs/disk/search) или `fileId` из ответа прошлой загрузки. Десятичное число строкой без ведущих нулей |
| `intent[3]` | string | да | SHA-256 исходных байтов файла — 64 символа в нижнем регистре |
| `intent[4]` | string | да | Размер файла в байтах, десятичное число строкой. Не больше `26214400` (25 МиБ) |
| `intent[5]` | null \| array | да | При `create` — `null`. При `version` — ожидаемое текущее состояние файла: массив из трёх строк `[contentFileId, contentGeneration, size]`. Значения — из карточки файла в [`POST /v1/disk/search`](/docs/disk/search) или из ответа прошлой загрузки |
| `intent[6]` | string | да | Имя файла на Диске. Не пустое и не из одних пробелов, без управляющих символов и без `<` `>` `:` `"` `\|` `?` `*` `\` `/` |
| `intent[7]` | string | да | Политика записи: `createFail` для режима `create`, `versionPreflightNoCAS` для режима `version`. Другая пара режима и политики даёт `400 INVALID_PARAMS` |
| `lineage` | object | да | Связь операции с прошлыми |
| `lineage.kind` | string | да | `initial` — первая загрузка с этим `intent`. `successor` — следующая версия файла после успешной операции: прошлая операция в состоянии `application: "applied"`, новый `intent` в режиме `version`, `intent[2]` равен `fileId` прошлой операции. `retry` — повтор того же `intent` после операции, завершённой с `application: "not_applied"` |
| `lineage.priorOperationId` | string | нет | Обязателен при `kind: "successor"` и `kind: "retry"`. `operationId` прошлой операции. Список операций: [`GET /v1/disk/uploads`](/docs/disk/uploads-list). При `kind: "initial"` поле не передаётся |

Других полей тело не принимает: неизвестное поле даёт `400 INVALID_PARAMS`.

## Примеры

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

```bash
curl -X POST https://vibecode.bitrix24.tech/v1/disk/uploads/reserve \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reserveRequestId": "docs-check-reserve-2",
    "intent": [1, "create", "1", "6be5cdb4cdbf136301c74adf2fd5a380fe5ceda1e998ce4b62f01cf7d20589a5", "29", null, "vibe-disk-docs-check-2.txt", "createFail"],
    "lineage": { "kind": "initial" }
  }'
```

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

```bash
curl -X POST https://vibecode.bitrix24.tech/v1/disk/uploads/reserve \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reserveRequestId": "docs-check-reserve-2",
    "intent": [1, "create", "1", "6be5cdb4cdbf136301c74adf2fd5a380fe5ceda1e998ce4b62f01cf7d20589a5", "29", null, "vibe-disk-docs-check-2.txt", "createFail"],
    "lineage": { "kind": "initial" }
  }'
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/disk/uploads/reserve', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    reserveRequestId: 'docs-check-reserve-2',
    intent: [1, 'create', '1', '6be5cdb4cdbf136301c74adf2fd5a380fe5ceda1e998ce4b62f01cf7d20589a5', '29', null, 'vibe-disk-docs-check-2.txt', 'createFail'],
    lineage: { kind: 'initial' },
  }),
})

const { success, data, error } = await res.json()
if (!success) throw new Error(error.code)
// Сохраните operationId и intentHash до загрузки содержимого
console.log(data.operationId, data.intentHash)
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/disk/uploads/reserve', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    reserveRequestId: 'docs-check-reserve-2',
    intent: [1, 'create', '1', '6be5cdb4cdbf136301c74adf2fd5a380fe5ceda1e998ce4b62f01cf7d20589a5', '29', null, 'vibe-disk-docs-check-2.txt', 'createFail'],
    lineage: { kind: 'initial' },
  }),
})

const { success, data, error } = await res.json()
```

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

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | `true` при успешном резерве |
| `data.operationId` | string | Идентификатор операции. Передаётся в [`POST /v1/disk/uploads`](/docs/disk/uploads) и [`GET /v1/disk/uploads/:operationId`](/docs/disk/uploads-get) |
| `data.phase` | string | Этап операции: `prepared` — зарезервирована, `submitting` — запись передана в Битрикс24, `settled` — завершена |
| `data.application` | string | Результат записи: `applied` — файл записан, `not_applied` — запись не выполнялась, `unknown` — результат неизвестен |
| `data.verification` | string | Сверка с текущим состоянием файла: `matched` — файл совпадает с записанным, `superseded` — файл с тех пор изменился, `unavailable` — сверка не выполнена |
| `data.intentHash` | string | SHA-256 от `intent`, записанного компактным JSON в UTF-8. Передаётся в [`POST /v1/disk/uploads`](/docs/disk/uploads) |
| `data.reservationExpiresAt` | string | Дата и время в ISO 8601, до которых операция принимает содержимое. Наступает через 30 дней после создания операции |
| `data.recovered` | boolean | `true` — вернулась операция, созданная раньше, `false` — создана новая |

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

Новый резерв:

```json
{
  "success": true,
  "data": {
    "operationId": "xykPPgOlNBiKMTlAV3SfBoGJhG6Hi6AX57Ede4rAFoU",
    "phase": "prepared",
    "application": "not_applied",
    "verification": "unavailable",
    "intentHash": "3e10ae1152a0e4b4e89d3b312bfacafc1f3e0cf22d8a5eae3e231fa8bc274498",
    "reservationExpiresAt": "2026-11-22T10:10:36.591Z",
    "recovered": false
  }
}
```

Повтор того же запроса после загрузки файла — та же операция в текущем состоянии:

```json
{
  "success": true,
  "data": {
    "operationId": "xykPPgOlNBiKMTlAV3SfBoGJhG6Hi6AX57Ede4rAFoU",
    "phase": "settled",
    "application": "applied",
    "verification": "matched",
    "intentHash": "3e10ae1152a0e4b4e89d3b312bfacafc1f3e0cf22d8a5eae3e231fa8bc274498",
    "reservationExpiresAt": "2026-11-22T10:10:36.591Z",
    "recovered": true
  }
}
```

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

409 — тот же `reserveRequestId` пришёл с другим `intent`:

```json
{
  "success": false,
  "error": {
    "code": "DISK_OPERATION_CONFLICT",
    "message": "Disk request unavailable",
    "retrySafe": false
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `INVALID_PARAMS` | Тело не прошло проверку: неверный состав `intent`, недопустимое имя файла, `lineage` без `priorOperationId` при `successor` или `retry`, неизвестное поле |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Ключ не опознан |
| 401 | `TOKEN_MISSING` | У ключа нет подключения к Битрикс24 |
| 401 | `DISK_AUTH_UNAVAILABLE` | Не удалось подтвердить пользователя Битрикс24: ключ приложения передан без `Authorization: Bearer`, сессия не принадлежит приложению ключа или ключ не поддерживается агентом Диска |
| 401 | `TOKEN_REFRESH_FAILED` | Не удалось обновить авторизацию портала для ключа. Повтор не поможет, пока ключ не авторизован заново |
| 403 | `SCOPE_DENIED` | У ключа нет скоупа `disk` |
| 403 | `WRITE_BLOCKED_READONLY` | Ключ в режиме «только чтение» |
| 403 | `DISK_ACCESS_DENIED` | Битрикс24 отказал в доступе при проверке пользователя |
| 409 | `DISK_OPERATION_CONFLICT` | `reserveRequestId` уже использован с другим `intent` или `lineage`. Либо у операции `priorOperationId` уже есть продолжение с другим `intent` или другим `lineage.kind` |
| 409 | `DISK_PRIOR_REQUIRED` | Операция `priorOperationId` не найдена или ещё не завершена, либо не выполнено условие `lineage.kind`: для `successor` — прошлая запись не `applied`, режим нового `intent` не `version` или `intent[2]` не равен её `fileId`, для `retry` — прошлая запись не `not_applied` или её `intent` другой |
| 409 | `DISK_OUTCOME_UNKNOWN` | Результат операции `priorOperationId` неизвестен: `application` равен `unknown`. Продолжение и повтор от неё не принимаются |
| 409 | `DISK_GENERATION_STALE` | Подключение ключа к Битрикс24 сменилось во время запроса. Повторите резерв |
| 413 | `DISK_UPLOAD_TOO_LARGE` | Размер `intent[4]` больше `26214400` байт |
| 502 | `DISK_READ_UNAVAILABLE` | Битрикс24 вернул ошибку, которую Вайбкод не распознал |
| 503 | `QUERY_LIMIT_EXCEEDED` | Битрикс24 ограничил частоту запросов. Повторите позже |
| 503 | `BITRIX_TIMEOUT` | Битрикс24 не ответил вовремя |
| 503 | `QUEUE_OVERFLOW`, `QUEUE_TIMEOUT` | Очередь вызовов портала переполнена. Заголовок `Retry-After` называет паузу перед повтором |
| 503 | `RATE_LIMITED` | Портал ответил HTTP 429. Паузу перед повтором называет заголовок `Retry-After` |
| 503 | `ERROR_LOOP_DETECTED` | Повторяющиеся ошибки этого ключа на этом методе временно остановили вызовы. Паузу называет заголовок `Retry-After` |
| 503 | `user_self_deletion_pending` | Владелец ключа запросил удаление своей учётной записи — обращения к Диску остановлены |

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

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

- **Резерв не передаёт байты и не обращается к папке или файлу.** Существование папки, права на запись и свободное имя проверяются только при загрузке содержимого в [`POST /v1/disk/uploads`](/docs/disk/uploads).
- **Одинаковый `intent` с `lineage.kind: "initial"` даёт одну операцию.** Новый `reserveRequestId` с тем же `intent` возвращает уже существующую операцию с `recovered: true`, в том числе завершённую.
- **У операции одно продолжение.** От одной прошлой операции принимается только одно продолжение `successor` или `retry`. Второй запрос с тем же `intent` и `lineage.kind` возвращает уже созданное продолжение.
- **Операции привязаны к контексту ключа.** Резерв, загрузка и чтение операций работают в рамках одного портала, одного пользователя Битрикс24 и одного источника авторизации: входящего вебхука личного ключа или OAuth-приложения. Из другого контекста операция не видна.

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

- [Загрузить содержимое файла на Диск](/docs/disk/uploads)
- [Получить операцию загрузки](/docs/disk/uploads-get)
- [Список операций загрузки](/docs/disk/uploads-list)
- [Поиск по Диску](/docs/disk/search)
- [Получить возможности Диска](/docs/disk/capabilities)
- [Ошибки](/docs/errors)
