#Хранилище

Хранилище файлов для Битрикс24-приложений: загружайте, управляйте видимостью и скачивайте по временным ссылкам.

Скоуп: vibe:storage | Базовый URL: https://vibecode.bitrix24.tech/v1 | Авторизация: API-ключ (X-Api-Key)

Авторизация · Жизненный цикл · Пути загрузки · Видимость · Ключ объекта · Лимиты · Тарификация · Быстрый старт · Полный пример · Эндпоинты · Ошибки

#Когда использовать

Подходит для:

  • Аватаров пользователей и логотипов приложения
  • Вложений в формах: фотографии, сканы, чеки
  • Экспортов и сгенерированных отчётов (CSV, PDF)
  • Видеовложений в CRM-сделках
  • Резервных копий конфигурации приложения
  • Промежуточных файлов в цепочке обработки данных

Не подходит для:

  • Публикации файлов в Диск Битрикс24 портала — для этого предназначен раздел Диск; хранилище изолировано по приложению и не входит в дисковое дерево портала
  • Хранения секретов и ключей — используйте переменные окружения сервера
  • Журналирования и аудита приложения
  • Сценариев без привязки к приложению — хранилище всегда изолировано по ключу

#Разделы документации

Раздел Описание
Загрузка Три пути загрузки: прямая форма (≤10 МБ), предподписанный PUT (≤5 ГБ), составные части (≤5 ТБ)
Объекты Список, получение, метаданные, удаление объектов и публичный доступ

#Авторизация

Все запросы к /v1/storage/* требуют API-ключ в заголовке X-Api-Key со скоупом vibe:storage.

Новые ключи получают скоуп vibe:storage автоматически. Если ключ создан до его появления — добавьте скоуп в разделе API-ключи личного кабинета.

Отсутствие скоупа возвращает 403 STORAGE_SCOPE_REQUIRED на любом вызове /v1/storage/*.

Типы ключей

Тип ключа Доступ Область хранилища
vibe_api_* — личный API-ключ да пространство имён владельца ключа на портале
vibe_app_* — ключ приложения да пространство имён приложения, к которому привязан ключ

Менеджмент-ключи (vibe_live_*) к /v1/storage/* не подходят — у них нет привязки к порталу. Любой вызов вернёт 403 STORAGE_REQUIRES_PORTAL_BINDING.

Изоляция. Объекты изолированы по владельцу ключа: ключ одного портала не получит доступ к объектам другого портала — такой запрос вернёт 404 STORAGE_OBJECT_NOT_FOUND, а не 403, чтобы не раскрывать существование чужих ресурсов.

#Жизненный цикл объекта

PENDING      — создан, ожидает загрузки файла (пути B и C)
    │
    ▼ (путь A → сразу COMPLETED)
COMPLETED    — файл загружен, доступен для чтения
    │
    ▼ (DELETE)
deletedAt    — мягкое удаление: чтение → 410; данные хранятся ещё 30 суток
    │
    ▼ (+30 суток, планировщик)
удалён       — данные стёрты из хранилища, квота освобождена

Прямая загрузка (путь A) создаёт объект сразу в состоянии COMPLETED. Пути B и C создают объект в состоянии PENDING — до вызова /complete.

Объекты в состоянии PENDING без завершения удаляются фоновым планировщиком через 24 часа.

#Пути загрузки

Путь Размер файла Шагов Когда применять
A — прямая загрузка до 10 МБ 1 Серверный код, небольшие файлы
B — предподписанный PUT до 5 ГБ 3 Загрузка из браузера без промежуточного сервера
C — составная загрузка до 5 ТБ 3 + N частей Крупные файлы, параллельная загрузка

Подробное описание каждого пути — Загрузка.

#Видимость и доступ

Каждый объект имеет атрибут visibility:

  • PRIVATE (по умолчанию) — скачивание через авторизованный запрос GET /v1/storage/objects/:key, который возвращает перенаправление 302 на предподписанный URL, действующий 10 минут.
  • PUBLIC — дополнительно доступен через постоянный URL вида https://vibecode.bitrix24.tech/v1/public-storage/:portalId/:objectId без авторизации.

Для PUBLIC-объектов заблокирована отдача файлов с типами содержимого text/html, application/javascript, application/x-javascript, image/svg+xml. Попытка загрузить файл с таким типом при visibility=PUBLIC возвращает 415 STORAGE_FORBIDDEN_CONTENT_TYPE.

Анонимный доступ через public-storage включается на стороне портала и по умолчанию выключен. Пока он выключен, запросы к публичному URL возвращают 503 STORAGE_PUBLIC_GET_DISABLED_FOR_PORTAL.

#Ключ объекта

Ключ объекта — уникальный идентификатор в пространстве имён, привязанном к вашему ключу (личное пространство владельца или пространство приложения). Правила:

  • Длина: 1–1024 символа.
  • Допустимые символы: a-z, A-Z, 0-9, ., _, /, -.
  • Не может начинаться с / или ..
  • Не может содержать последовательность ...
  • Символ / — разделитель пути, используется для группировки по префиксу.

В параметрах пути URL слеши в ключе необходимо кодировать: encodeURIComponent('users/42/report.csv') возвращает 'users%2F42%2Freport.csv'.

#Лимиты

Параметр Значение
Максимальный размер файла (путь A) 10 МБ
Максимальный размер файла (путь B) 5 ГБ
Максимальный размер файла (путь C) 5 ТБ
Длина ключа объекта 1–1024 символа
Срок действия предподписанного URL 10 минут
Период мягкого удаления 30 суток
Объекты в состоянии PENDING удаляются через 24 часа
Лимит запросов к публичному URL 60 запросов/мин с одного IP

#Тарификация

Хранилище работает по схеме оплаты по факту использования.

Ресурс Ставка
Хранение 1,96 Ꝟ/ГБ-месяц
Исходящий трафик 1,20 Ꝟ/ГБ
Операции 0,50 Ꝟ / 1 000 операций записи

При нулевом балансе запросы на запись блокируются на 24 часа. Чтение объектов продолжает работать. Пополнение баланса разблокирует запись немедленно.

Текущее использование и прогноз расходов — в блоке storage ответа GET /v1/me. Владелец портала также видит сводный расход по приложениям и может выгрузить отчёт на странице Хранилище в админ-панели портала.

#Использование в AI-агентах

AI-моделям и агентам хранилище доступно без чтения этой страницы:

  • Блок storage в ответе GET /v1/me — состояние хранилища, ставки, пути загрузки и список эндпоинтов.
  • Инструменты vibe_storage_* MCP-сервера (загрузка, предподписанные ссылки, список, удаление, контроль расхода) — см. MCP для AI.

#Быстрый старт

Загрузить файл (путь A):

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/storage/objects/upload \
  -H "X-Api-Key: YOUR_API_KEY" \
  -F "key=reports/march.csv" \
  -F "visibility=PRIVATE" \
  -F "file=@march.csv;type=text/csv"

Получить ссылку для скачивания:

Terminal
curl -I \
  -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.tech/v1/storage/objects/reports%2Fmarch.csv"
# HTTP/1.1 302 Found
# Location: <временная ссылка на объект, действует 10 минут>

#Полный пример

Полный цикл: загрузка → список → получение ссылки → удаление.

javascript
const KEY = 'YOUR_API_KEY'
const BASE = 'https://vibecode.bitrix24.tech/v1'

const form = new FormData()
form.append('key', 'users/42/report.csv')
form.append('visibility', 'PRIVATE')
form.append('file', new Blob(['id,name\n1,Alice\n2,Bob'], { type: 'text/csv' }), 'report.csv')

const uploadRes = await fetch(`${BASE}/storage/objects/upload`, {
  method: 'POST',
  headers: { 'X-Api-Key': KEY },
  body: form,
})
const { object } = await uploadRes.json()
console.log('Загружен:', object.key, '| uploadStatus:', object.uploadStatus)

const listRes = await fetch(`${BASE}/storage/objects?prefix=users/42`, {
  headers: { 'X-Api-Key': KEY },
})
const { data, total } = await listRes.json()
console.log('Объектов:', total, '| первый:', data[0]?.key)

const getRes = await fetch(`${BASE}/storage/objects/${encodeURIComponent(object.key)}`, {
  headers: { 'X-Api-Key': KEY },
  redirect: 'manual',
})
const downloadUrl = getRes.headers.get('location')
console.log('Ссылка (10 мин):', downloadUrl)

const delRes = await fetch(`${BASE}/storage/objects/${encodeURIComponent(object.key)}`, {
  method: 'DELETE',
  headers: { 'X-Api-Key': KEY },
})
const { object: deleted } = await delRes.json()
console.log('Удалён:', deleted.key, '| deletedAt:', deleted.deletedAt)

#Типовые сценарии

#Большой файл составной загрузкой

Загрузка крупного файла по частям с отменой при ошибке (чтобы не оплачивать незавершённые части):

javascript
const KEY = 'YOUR_API_KEY'
const BASE = 'https://vibecode.bitrix24.tech/v1'
const PART_SIZE = 8 * 1024 * 1024 // 8 МБ

// file — File или Blob, например из <input type="file">
const init = await fetch(`${BASE}/storage/objects/multipart/create`, {
  method: 'POST',
  headers: { 'X-Api-Key': KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    key: 'videos/demo.mp4',
    contentType: 'video/mp4',
    totalSize: file.size,
    partSize: PART_SIZE,
    visibility: 'PRIVATE',
  }),
})
const { objectId, parts } = await init.json()

try {
  const uploaded = []
  for (const part of parts) {
    const chunk = file.slice((part.partNumber - 1) * PART_SIZE, part.partNumber * PART_SIZE)
    const res = await fetch(part.uploadUrl, { method: 'PUT', body: chunk })
    uploaded.push({ partNumber: part.partNumber, etag: res.headers.get('etag') })
  }
  const done = await fetch(`${BASE}/storage/objects/multipart/complete`, {
    method: 'POST',
    headers: { 'X-Api-Key': KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ objectId, parts: uploaded }),
  })
  const { object } = await done.json()
  console.log('Загружен:', object.key, object.sizeBytes)
} catch (err) {
  await fetch(`${BASE}/storage/objects/multipart/abort`, {
    method: 'POST',
    headers: { 'X-Api-Key': KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ objectId }),
  })
  throw err
}

#Массовая чистка по префиксу

Удаление всех файлов пользователя при его отключении: постраничный обход по префиксу и удаление каждого объекта.

javascript
const KEY = 'YOUR_API_KEY'
const BASE = 'https://vibecode.bitrix24.tech/v1'

async function deleteByPrefix(prefix) {
  let cursor = null
  let removed = 0
  do {
    const url = new URL(`${BASE}/storage/objects`)
    url.searchParams.set('prefix', prefix)
    url.searchParams.set('limit', '500')
    if (cursor) url.searchParams.set('cursor', cursor)

    const page = await fetch(url, { headers: { 'X-Api-Key': KEY } })
    const { data, cursor: next } = await page.json()

    for (const obj of data) {
      await fetch(`${BASE}/storage/objects/${encodeURIComponent(obj.key)}`, {
        method: 'DELETE',
        headers: { 'X-Api-Key': KEY },
      })
      removed++
    }
    cursor = next
  } while (cursor)
  return removed
}

const count = await deleteByPrefix('users/42/')
console.log('Удалено объектов:', count)

#Справочник эндпоинтов

#Загрузка

Метод Путь Описание
POST `/v1/storage/objects/upload` Прямая загрузка файла до 10 МБ одним multipart/form-data-запросом
POST `/v1/storage/objects` Создать предподписанный URL для загрузки файла до 5 ГБ напрямую в хранилище
POST `/v1/storage/objects/complete` Подтвердить завершение загрузки по предподписанному URL
POST `/v1/storage/objects/multipart/create` Инициировать составную загрузку: получить идентификатор сессии и URL для частей
POST `/v1/storage/objects/multipart/complete` Собрать объект из загруженных частей по их partNumber и etag
POST `/v1/storage/objects/multipart/abort` Отменить составную загрузку и удалить незавершённые части

#Объекты

Метод Путь Описание
GET `/v1/storage/objects` Список объектов с фильтрацией по префиксу и курсорной пагинацией
GET `/v1/storage/objects/:key` Скачать объект (перенаправление 302 → предподписанный URL)
HEAD `/v1/storage/objects/:key` Метаданные объекта без тела ответа
DELETE `/v1/storage/objects/:key` Мягкое удаление объекта

#Публичный доступ

Метод Путь Описание
GET `/v1/public-storage/:portalId/:objectId` Скачать PUBLIC-объект без API-ключа
HEAD `/v1/public-storage/:portalId/:objectId` Метаданные PUBLIC-объекта без API-ключа

#Коды ошибок

Код HTTP Когда возникает
STORAGE_SCOPE_REQUIRED 403 API-ключ не имеет скоупа vibe:storage
STORAGE_NO_AUTH_CONTEXT 401 Запрос без пригодных учётных данных приложения
STORAGE_KEY_REQUIRED 400 Поле key не передано или пустое
STORAGE_INVALID_KEY 400 Ключ содержит недопустимые символы, начинается с / или ., содержит ..
STORAGE_INVALID_PATH 400 Ключ формирует инъекцию пути
STORAGE_CONTENT_TYPE_REQUIRED 400 Поле contentType не передано (пути B и C)
STORAGE_INVALID_VISIBILITY 400 visibility не равен PUBLIC или PRIVATE
STORAGE_INVALID_SIZE 400 sizeBytes не является неотрицательным целым числом
STORAGE_INVALID_TTL 400 ttlSeconds вне диапазона 60–86400
STORAGE_FILE_REQUIRED 400 Файловая часть в форме не передана (путь A)
STORAGE_MULTIPART_PARSE_FAILED 400 Ошибка разбора multipart/form-data
STORAGE_OBJECT_ID_REQUIRED 400 Параметр objectId не передан
STORAGE_INVALID_TOTAL_SIZE 400 totalSize не является положительным целым числом (путь C)
STORAGE_INVALID_PART_SIZE 400 partSize не является положительным целым числом (путь C)
STORAGE_PARTS_REQUIRED 400 Массив parts не передан или пуст
STORAGE_INVALID_PART 400 Элемент массива parts не соответствует формату { partNumber, etag }
STORAGE_INVALID_PARTS 400 Набор частей отклонён хранилищем при сборке составной загрузки
STORAGE_TOO_MANY_PARTS 400 Слишком много частей для составной загрузки; увеличьте partSize
STORAGE_INVALID_LIMIT 400 limit не является положительным целым числом
STORAGE_UPLOAD_TOO_LARGE 413 Размер файла превышает 10 МБ (путь A)
STORAGE_OBJECT_TOO_LARGE 413 totalSize превышает 5 ТБ (путь C)
STORAGE_FORBIDDEN_CONTENT_TYPE 415 Тип содержимого недопустим для PUBLIC-объектов
STORAGE_OBJECT_NOT_FOUND 404 Объект не найден или не принадлежит вызывающему приложению
STORAGE_UPLOAD_NOT_PENDING 409 Объект уже загружен или находится в недопустимом состоянии
STORAGE_UPLOAD_PENDING 409 Попытка чтения объекта, загрузка которого не завершена
STORAGE_UPLOAD_NOT_FOUND_IN_BUCKET 409 PUT-запрос к предподписанному URL не был выполнен
STORAGE_MULTIPART_IN_PROGRESS 409 У объекта есть незавершённая составная загрузка; вызовите /multipart/abort
STORAGE_OBJECT_DELETED 410 Объект помечен как удалённый
STORAGE_QUOTA_EXCEEDED 507 Превышена квота хранилища приложения
BILLING_INSUFFICIENT 402 Нулевой баланс портала — запись приостановлена на 24 часа (чтение работает)
STORAGE_RATE_LIMIT_EXCEEDED 429 Превышен лимит 60 запросов/мин к публичному URL с одного IP
STORAGE_PUBLIC_GET_DISABLED_FOR_PORTAL 503 Публичный доступ отключён на уровне портала
STORAGE_FEATURE_DISABLED 503 Хранилище временно отключено
STORAGE_STS_UNAVAILABLE 503 Сервис выдачи временных учётных данных недоступен
STORAGE_BUCKET_ERROR 502 Ошибка при обращении к объектному хранилищу
STORAGE_OBJECT_MISSING_IN_BUCKET 502 Объект зафиксирован в базе, но отсутствует в хранилище
STORAGE_OBJECT_STREAM_FAILED 502 Ошибка при передаче данных объекта
STORAGE_OBJECT_HEAD_FAILED 502 Ошибка при получении метаданных объекта из хранилища

Общие коды ошибок API — Коды ошибок.

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