Для AI-агентов: markdown этой страницы — /docs-content/storage/upload/multipart-create.md индекс документации — /llms.txt

Создать составную загрузку

POST /v1/storage/objects/multipart/create

Открывает сессию составной загрузки для файлов до 5 ТБ. Возвращает идентификатор объекта, идентификатор сессии и предподписанные URL для загрузки частей. После загрузки всех частей вызовите POST /v1/storage/objects/multipart/complete, чтобы собрать объект.

На свободном key путь C создаёт новый объект. Живой app-bound объект COMPLETED той же owner tuple он заменяет в той же строке: ответ возвращает прежний objectId, а чтение отдаёт старое содержимое, пока /multipart/complete не опубликовал новые байты. Успешный ответ complete подтверждает новую версию; 502 STORAGE_BUCKET_ERROR может означать публикацию без подтверждённого результата. Подтверждённая отмена до публикации сохраняет старое содержимое.

Живой объект личного ключа (appId = null) путь C не заменяет. Сначала удалите объект через DELETE /v1/storage/objects/{key}, затем снова начните составную загрузку под тем же key. Это неатомарная операция: между удалением и успешным /multipart/complete объект недоступен. Подходящая удалённая строка COMPLETED личного ключа переиспользуется с прежними objectId и visibility; для других удалённых состояний возвращается 409 STORAGE_KEY_DELETED.

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

Тело запроса — JSON.

Параметр Тип Обяз. По умолч. Описание
key string да — Логический ключ объекта: от 1 до 1024 символов, допустимы a-z, A-Z, 0-9, ., _, /, -; не начинать с / или ., не содержать ..
contentType string да — MIME-тип файла, например video/mp4 или application/zip
totalSize number да — Общий размер файла в байтах; положительное целое число; не более 5 ТБ (5 497 558 138 880 байт)
partSize number нет 8388608 Размер одной части в байтах; от 5 МБ (5 242 880) до 5 ГБ (5 368 709 120); последняя часть может быть меньше минимума
visibility string нет PRIVATE для нового объекта Видимость объекта: PRIVATE или PUBLIC. При замене не передавайте поле либо передайте сохранённое значение

Примеры

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

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/storage/objects/multipart/create \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "videos/lecture-01.mp4",
    "contentType": "video/mp4",
    "totalSize": 209715200
  }'

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

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/storage/objects/multipart/create \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "videos/lecture-01.mp4",
    "contentType": "video/mp4",
    "totalSize": 209715200
  }'

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

javascript
const file = fileInput.files[0]

// Шаг 1 — открыть сессию составной загрузки
const createRes = await fetch(
  'https://vibecode.bitrix24.tech/v1/storage/objects/multipart/create',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      key: 'videos/lecture-01.mp4',
      contentType: file.type,
      totalSize: file.size,
    }),
  }
)
const { objectId, parts } = await createRes.json()

// Шаг 2 — загрузить части параллельно, сохранить ETag из заголовков ответов
const PART_SIZE = 8 * 1024 * 1024
const uploadedParts = await Promise.all(
  parts.map(async ({ partNumber, uploadUrl }) => {
    const start = (partNumber - 1) * PART_SIZE
    const end = Math.min(start + PART_SIZE, file.size)

    const putRes = await fetch(uploadUrl, {
      method: 'PUT',
      body: file.slice(start, end),
    })
    const etag = putRes.headers.get('ETag')
    return { partNumber, etag }
  })
)

// Шаг 3 — завершить сборку объекта
const completeRes = await fetch(
  'https://vibecode.bitrix24.tech/v1/storage/objects/multipart/complete',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ objectId, parts: uploadedParts }),
  }
)
const { object } = await completeRes.json()
console.log('Object ID:', object.id)

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

javascript
const file = fileInput.files[0]

const createRes = await fetch(
  'https://vibecode.bitrix24.tech/v1/storage/objects/multipart/create',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      key: 'videos/lecture-01.mp4',
      contentType: file.type,
      totalSize: file.size,
    }),
  }
)
const { objectId, parts } = await createRes.json()

const PART_SIZE = 8 * 1024 * 1024
const uploadedParts = await Promise.all(
  parts.map(async ({ partNumber, uploadUrl }) => {
    const start = (partNumber - 1) * PART_SIZE
    const end = Math.min(start + PART_SIZE, file.size)

    const putRes = await fetch(uploadUrl, { method: 'PUT', body: file.slice(start, end) })
    const etag = putRes.headers.get('ETag')
    return { partNumber, etag }
  })
)

const completeRes = await fetch(
  'https://vibecode.bitrix24.tech/v1/storage/objects/multipart/complete',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ objectId, parts: uploadedParts }),
  }
)
const { object } = await completeRes.json()

Поля ответа

Поле Тип Описание
objectId string Идентификатор объекта в хранилище
uploadId string Идентификатор сессии составной загрузки
partCount number Количество частей, рассчитанное из totalSize и partSize
parts array Массив описателей частей
parts[].partNumber number Номер части (начиная с 1)
parts[].uploadUrl string Предподписанный URL для загрузки части методом PUT; подпись фиксирует точный размер этой части, включая остаток последней части
parts[].expiresAt string Срок действия URL части (ISO 8601), взятый из подписи ссылки. Может быть короче 24 часов сессии

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

JSON
{
  "objectId": "cmpfg012a01aco510mrr6u632",
  "uploadId": "00065252B4EA33D1",
  "partCount": 2,
  "parts": [
    {
      "partNumber": 1,
      "uploadUrl": "https://storage.example.com/upload?partNumber=1&uploadId=00065252B4EA33D1&...",
      "expiresAt": "2026-05-22T12:03:56.398Z"
    },
    {
      "partNumber": 2,
      "uploadUrl": "https://storage.example.com/upload?partNumber=2&uploadId=00065252B4EA33D1&...",
      "expiresAt": "2026-05-22T12:03:56.398Z"
    }
  ]
}

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

413 — файл превышает ограничение 5 ТБ:

JSON
{
  "success": false,
  "error": {
    "code": "STORAGE_OBJECT_TOO_LARGE",
    "message": "Object exceeds 5 TB cap"
  }
}

Ошибки

HTTP Код Описание
403 STORAGE_SCOPE_REQUIRED API-ключу не хватает скоупа vibe:storage
409 STORAGE_KEY_EXISTS Личный ключ (appId = null) уже занят живым объектом. Удалите объект, затем начните загрузку снова. Операция неатомарна: до успешного завершения новый объект недоступен
409 STORAGE_KEY_DELETED Удалённая строка не подходит для повторной загрузки путём C. Переиспользуется только COMPLETED-строка личного ключа без активной multipart-сессии
409 STORAGE_MULTIPART_IN_PROGRESS По этому ключу уже идёт составная загрузка — завершите или отмените её
409 STORAGE_UPLOAD_PENDING По этому ключу висит незавершённая бронь предподписанной ссылки
409 STORAGE_KEY_OWNED_ELSEWHERE Имя занято объектом другого типа владения (общий файл приложения против персонального файла сотрудника). Другой сотрудник это же имя не блокирует
409 STORAGE_KEY_CONFLICT Повторяемый конфликт: адрес занят параллельной записью либо объект изменился при создании сессии. Повторите ту же операцию create
401 STORAGE_NO_AUTH_CONTEXT Запрос выполнен без авторизации
400 STORAGE_INVALID_PATH Идентификатор вызывающего содержит недопустимые символы пути
400 STORAGE_KEY_REQUIRED Не передано поле key
400 STORAGE_INVALID_KEY Значение key нарушает правила формата
400 STORAGE_CONTENT_TYPE_REQUIRED Не передано поле contentType
400 STORAGE_INVALID_VISIBILITY Недопустимое значение visibility
400 STORAGE_VISIBILITY_MISMATCH Замена не может изменить видимость объекта — не передавайте visibility либо передайте сохранённое значение
400 STORAGE_INVALID_TOTAL_SIZE totalSize не является положительным целым числом
400 STORAGE_INVALID_PART_SIZE partSize выходит за пределы допустимого диапазона (5 МБ – 5 ГБ) или не является положительным целым числом
413 STORAGE_OBJECT_TOO_LARGE totalSize превышает 5 ТБ
415 STORAGE_FORBIDDEN_CONTENT_TYPE Для PUBLIC-объектов запрещены типы text/html, application/javascript, application/x-javascript, image/svg+xml — Коды ошибок
400 STORAGE_TOO_MANY_PARTS Рассчитанное количество частей превышает 10 000 — увеличьте partSize
402 BILLING_INSUFFICIENT Недостаточно средств на балансе
507 STORAGE_QUOTA_EXCEEDED Заявленный totalSize не помещается в остаток потолка объёма хранилища портала. Отказ приходит до создания сессии, поэтому части не загружаются. Потолок необязательный, включается платформой и действует только для порталов, у которых нет и никогда не было коммерческого тарифа Битрикс24
503 STORAGE_FEATURE_DISABLED Хранилище отключено для портала
503 STORAGE_STS_UNAVAILABLE Служба выдачи временных учётных данных недоступна
502 STORAGE_BUCKET_ERROR Ошибка при взаимодействии с хранилищем

Полный список общих ошибок API — Ошибки.

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

Предподписанные URL для частей не требуют заголовков авторизации. Запросы PUT на эти URL отправляются напрямую в хранилище без X-Api-Key или Authorization — все необходимые учётные данные уже подписаны в самом URL.

Автоматическая очистка — через 24 часа. После 24 часов планировщик пытается отменить незавершённую сессию. Незагруженные части удаляются только после того, как провайдер подтвердил отмену. При неподтверждённой отмене сессия удерживается, а освобождение требует повторной попытки отмены либо участия оператора. Срок действия каждого предподписанного URL части — отдельный: он берётся из подписи ссылки, возвращается в parts[].expiresAt и может быть короче 24 часов. Отправляйте части как можно раньше, сверяясь с parts[].expiresAt, а не со сроком автоматической очистки. Для досрочного освобождения ресурсов вызовите POST /v1/storage/objects/multipart/abort.

Публикация новой версии. Во время multipart-замены чтение отдаёт прежнюю версию, пока /multipart/complete не опубликовал новые байты. Успешный ответ complete подтверждает новую версию под тем же objectId; 502 STORAGE_BUCKET_ERROR может означать, что публикация состоялась без подтверждённого результата. Подтверждённый /multipart/abort до публикации сохраняет прежнюю версию. Автоматическая очистка освобождает подтверждённо незавершённые части или завершает зафиксированную публикацию новой версии; неподтверждённый исход сохраняет сессию для операторской сверки.

Файлы меньшего размера. Для файлов до 10 МБ используйте прямую загрузку (Путь A). Путь B временно отключён и отвечает 503 STORAGE_PRESIGNED_UPLOAD_DISABLED, поэтому промежуточный размер тоже идёт составной загрузкой.

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