#Хранилище исходного кода
Хранилище исходного кода автоматически сохраняет снимки кода вашего приложения при каждом деплое. Если над приложением начинает работать другой человек или новая AI-сессия, последнюю версию можно скачать и продолжить с того же места — код не потеряется.
#Зачем это нужно
Когда вы дорабатываете приложение, важно не потерять рабочую версию кода. Хранилище делает это автоматически: при каждом успешном деплое платформа сохраняет снимок исходников. Если позже над приложением начнёт работать другой человек или новая AI-сессия — он скачает последнюю версию и продолжит с того же места, без ручной пересылки архивов.
Снимок привязан к приложению, а не к конкретному разработчику: код остаётся у приложения, даже если меняется команда.
#Чем это отличается от Git и GitHub
Это не система контроля версий и не замена Git. Хранилище решает более узкую задачу — страховка и передача проекта.
| Хранилище исходного кода | Git / GitHub | |
|---|---|---|
| Что хранит | целые снимки архива кода | историю изменений построчно |
| Когда сохраняет | автоматически при каждом деплое | вручную, по команде разработчика |
| Нужны ли навыки Git | нет | да |
| Ветки, слияния, сравнение версий | нет | да |
Нужна командная разработка с ветками и историей — используйте Git. Нужно просто не терять рабочий код и уметь вернуться к прошлой версии — достаточно хранилища.
#Как это работает
- Вы дорабатываете приложение и запускаете деплой.
- Платформа сама сохраняет снимок исходников — очередную версию:
v1,v2,v3, … - В любой момент смотрите список версий и скачиваете нужную.
- Перед публикацией приложения платформа проверяет, что свежий снимок есть.
правка кода → деплой → снимок vN сохранён автоматически
↓
список версий → скачать любую → продолжить работу
#Основные понятия
- Снимок (снапшот) — заархивированная копия исходного кода приложения на момент сохранения.
- Версия
vN— порядковый номер снимка (v1,v2, …). Самый свежий считается текущим. - Тег — метка
manualилиpublished: помечает версию как важную, чтобы её не удалила автоматическая очистка. - Дедупликация — если код не изменился, новый снимок не создаётся, возвращается уже существующая версия.
#Доступ и эндпоинты
Базовый URL: https://vibecode.bitrix24.tech/v1
Авторизация: заголовок X-Api-Key. Управлять снапшотами могут ключ авторизации приложения (vibe_app_*), личный ключ автора приложения (vibe_api_*) или администратор портала.
Допустимые форматы архива: application/gzip, application/x-tar, application/zip, application/octet-stream.
Лимит тела: 200 МБ на один запрос.
Эндпоинты:
| Метод | Путь | Действие |
|---|---|---|
POST |
/v1/apps/:id/sources |
Сохранить снапшот |
GET |
/v1/apps/:id/sources |
Список версий |
GET |
/v1/apps/:id/sources/:versionId/download |
Подписанная ссылка на скачивание |
PATCH |
/v1/apps/:id/sources/:versionId |
Обновить теги / комментарий |
POST |
/v1/apps/:id/sources/:versionId/tag |
Добавить или снять тег |
DELETE |
/v1/apps/:id/sources/:versionId |
Удалить версию |
POST |
/v1/apps/:id/sources/cleanup |
Массовая очистка старых версий |
#Сохранение исходников
С версии 2026-05-23 платформа автоматически сохраняет байты исходников в хранилище при каждом успешном развёртывании. Это касается:
POST /v1/infra/servers/:id/deploy { source: { content: <base64> } }— встроенные байты сохраняются как новая версияPOST /v1/infra/servers/:id/deploy { source: { url: <signed URL из хранилища> } }— существующая версия привязывается к идентификатору развёртыванияPOST /v1/infra/servers/:id/deploy { source: { versionId: 'vN' } }— то же
Исключение: развёртывание с внешним URL (не из хранилища Вайбкод) возвращает 409 SNAPSHOT_REQUIRED. Чтобы обойти — либо сначала загрузите архив через POST /v1/apps/:id/sources и разверните через {source: {versionId: 'vN'}}, либо передайте заголовок X-Skip-Source-Snapshot: <reason> для явного отказа.
#Когда снапшот не создаётся
Если сохранение исходников отключено на портале или источник — внешний URL (не хранилище Вайбкод), снапшот не создаётся, а развёртывание завершается штатно. Чтобы сохранить версию явно, загрузите архив через POST /v1/apps/:id/sources.
#Когда `POST /sources` всё ещё нужен явно
Только три сценария:
- Пометить версию — поставить тег
manualилиpublished, чтобы версия хранилась бессрочно. - Сохранить без развёртывания — зафиксировать промежуточный результат для передачи другому разработчику.
- Подготовка к откату — снимок исходного состояния перед рискованным изменением.
#Когда вызывать
Типовой сценарий для AI-агента (с 2026-05-23 явный вызов POST /sources перед деплоем не требуется — платформа сохраняет автоматически):
- Изменил код →
POST /v1/infra/servers/:id/deploy— исходники сохраняются автоматически. POST /v1/apps/:id/publish— публикует приложение в каталоге Битрикс24. Тегpublishedдобавляется к снапшоту автоматически.- Повторил цикл при следующем изменении.
Сценарий передачи проекта новому разработчику или новой AI-сессии:
GET /v1/apps/:id/sources— список доступных версий.GET /v1/apps/:id/sources/:versionId/download— подписанная ссылка на архив.- Скачать архив, распаковать и продолжить работу.
Для MCP-клиентов: инструмент save_sources упаковывает файловое дерево в tar.gz на стороне клиента и отправляет одним запросом. Инструмент load_sources загружает последнюю версию и распаковывает обратно в дерево файлов. Прямой вызов HTTP-эндпоинта доступен для клиентов, которые самостоятельно упаковывают архив.
#Гарантия наличия снапшота перед публикацией
POST /v1/apps/:id/publish проверяет наличие снапшота не старше 10 минут. Если снапшота нет или он устарел — возвращается 409 SNAPSHOT_REQUIRED с подсказкой, какой вызов нужно сделать перед повторной публикацией.
Проверка работает только если в портале включено сохранение исходников (по умолчанию включено, владелец портала может отключить — см. раздел «Отключение для портала»).
Пример отказа:
{
"success": false,
"error": {
"code": "SNAPSHOT_REQUIRED",
"message": "Deploy requires a recent source snapshot. Call POST /v1/apps/:id/sources first.",
"hint": {
"requiredAction": "POST /v1/apps/:id/sources",
"toolName": "save_sources",
"freshnessWindowMinutes": 10,
"lastSnapshot": {
"versionId": "v3",
"timestamp": "2026-05-21T09:42:11.000Z",
"ageMinutes": 23
}
}
}
}
Поле hint.lastSnapshot равно null, если для приложения ещё нет ни одного снапшота.
Параметры для повторной публикации той же версии (не самой свежей):
sourceVersionIdв теле — форматv<N>, например"sourceVersionId": "v3".- Заголовок
x-source-version: v3— альтернатива телу.
#Срок жизни версий (политика хранения)
После сохранения версия проходит через автоматическую очистку по графику «дед-отец-сын» (Grandfather-Father-Son):
- Последние 5 версий хранятся всегда, независимо от тегов.
- Дневная сетка за 14 дней — одна версия на каждый календарный день (UTC).
- Недельная сетка за 4 недели — одна версия на каждые 7 дней.
- Теги
publishedиmanual— хранятся бессрочно, никогда не удаляются автоматически.
Для пользовательской очистки на запрос — POST /v1/apps/:id/sources/cleanup. Версии с тегами published и manual исключаются и из неё.
#Сохранение снапшота
POST /v1/apps/:id/sources
Принимает сырые байты архива исходного кода в теле запроса. Формат определяется заголовком Content-Type. Метаданные (теги, комментарий, имя файла) передаются через дополнительные заголовки.
Только бинарная загрузка (контракт v2). Эндпоинт принимает сырые байты архива в теле запроса (
--data-binary).multipart/form-dataбольше не поддерживается — такой запрос возвращает400 INVALID_CONTENT_TYPE. Ранние версии клиентов, которые слалиmultipart/form-dataс полями формы (-F "tag=manual"), нужно обновить: тело — это сами байты архива, а теги, комментарий и имя файла передаются заголовкамиX-Tags/X-Note/X-Filename(не полями формы и не query-параметрами). MCP-клиенты используют инструментsave_sources, который сам упаковывает и отправляет архив в правильном формате.
#Параметры пути
| Параметр | Тип | Описание |
|---|---|---|
id (path) |
UUID | Идентификатор приложения. Получить — `GET /v1/apps`. |
#Заголовки запроса
| Заголовок | Обязательный | Описание |
|---|---|---|
Content-Type |
да | Формат архива. Допустимые значения: application/gzip, application/x-tar, application/zip, application/octet-stream. Любое другое значение → 400 INVALID_CONTENT_TYPE. |
X-Filename |
нет | Произвольное имя файла для отображения (например, app-v1.tar.gz). Если не указан — имя выводится из Content-Type (например, source.tar.gz для application/gzip). |
X-Tags |
нет | Теги через запятую. Распознаются manual и published — они защищают версию от автоматической очистки. |
X-Note |
нет | Произвольный комментарий, который сохраняется в записи о версии. |
X-AI-Session-Id |
нет | Идентификатор AI-сессии. Группирует снапшоты в манифесте по сессии. |
#Тело запроса
Сырые байты архива, не multipart/form-data. Максимальный размер — 200 МБ.
#Ответ при успешном сохранении
HTTP 201:
{
"success": true,
"data": {
"versionId": "v3",
"id": "b7c1e2a4-9f5d-4c3a-8e21-0a1b2c3d4e5f",
"filename": "2026-05-21T10-15-30-000Z-v3.tar.gz",
"contentType": "application/gzip",
"sha256": "a3f5d8b2c1e9f4...",
"size": 184320,
"timestamp": "2026-05-21T10:15:30.000Z",
"tags": [],
"note": null,
"deduplicated": false
}
}
#Поля ответа
| Поле | Тип | Описание |
|---|---|---|
data.versionId |
string | Идентификатор версии вида v<N>. |
data.id |
string | Внутренний идентификатор записи снапшота (UUID). |
data.filename |
string | Имя файла архива в хранилище. |
data.contentType |
string | Тип архива: application/gzip, application/zip, application/x-tar или application/octet-stream. |
data.sha256 |
string | SHA-256 содержимого архива. Используется для дедупликации. |
data.size |
number | Размер архива в байтах. |
data.timestamp |
string | Время сохранения (ISO 8601, UTC). |
data.tags |
string[] | Активные теги версии: manual, published. |
data.note |
string | null | Комментарий из заголовка X-Note или null. |
data.deduplicated |
boolean | true, если архив с тем же содержимым уже был сохранён — возвращена существующая версия. |
#Идемпотентность
Повторное сохранение архива с тем же содержимым даёт тот же sha256 и не создаёт новую версию. Эндпоинт возвращает HTTP 201 с deduplicated: true и versionId уже существующей версии. Если при повторном сохранении переданы новые теги или комментарий — они добавляются к существующей версии (теги объединяются, комментарий перезаписывается).
В обоих случаях обновляется метка App.lastSourceSavedAt — проверка свежести перед POST /v1/apps/:id/publish принимает дедуплицированное сохранение наравне с настоящим.
#Ответ при отключённом сохранении
HTTP 200 — снапшот не создан:
{
"success": true,
"data": {
"skipped": true,
"reason": "DISABLED_GLOBALLY"
}
}
reason — "DISABLED_GLOBALLY" (платформа не включила функцию) или "DISABLED_FOR_PORTAL" (владелец портала отключил для своего портала). При любом из вариантов POST /v1/apps/:id/publish не проверяет наличие снапшота.
#Примеры
#curl — tar.gz
curl -X POST https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Content-Type: application/gzip" \
-H "X-Note: Добавил OAuth-флоу" \
-H "X-Tags: manual" \
--data-binary @app-sources.tar.gz
#curl — zip
curl -X POST https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Content-Type: application/zip" \
--data-binary @app-sources.zip
#JavaScript
const archive = await fs.readFile('app-sources.tar.gz')
const res = await fetch(
`https://vibecode.bitrix24.tech/v1/apps/${appId}/sources`,
{
method: 'POST',
headers: {
'X-Api-Key': process.env.VIBE_APP_KEY,
'Content-Type': 'application/gzip',
'X-Note': 'Добавил OAuth-флоу',
},
body: archive,
},
)
const json = await res.json()
console.log(json.data.versionId, 'deduplicated:', json.data.deduplicated)
#Коды ошибок
| HTTP | Код | Когда возвращается |
|---|---|---|
| 400 | INVALID_CONTENT_TYPE |
Content-Type не входит в список допустимых форматов архива. Формат multipart/form-data не принимается — отправляйте сырые байты архива. |
| 400 | INVALID_BLOB |
Тело запроса не является бинарным буфером (например, передан текст). |
| 400 | INVALID_FILENAME |
Заголовок X-Filename содержит символы вне набора a-zA-Z0-9._-. |
| 400 | INVALID_TAGS |
Тег из заголовка X-Tags содержит недопустимые символы (разрешены a-zA-Z0-9_-). |
| 403 | NOT_AUTHORIZED |
Только автор приложения, OAuth-ключ приложения или администратор портала могут управлять снапшотами. |
| 404 | APP_NOT_FOUND |
Приложение не существует, удалено или принадлежит другому порталу. |
| 413 | — | Размер архива превышает лимит в 200 МБ. |
| 500 | SOURCE_STORAGE_ERROR |
Внутренняя ошибка хранилища. |
#Обновление метаданных версии
PATCH /v1/apps/:id/sources/:versionId
Обновляет теги и/или комментарий существующей версии без повторной загрузки архива. Удобно, если нужно добавить тег или скорректировать комментарий задним числом.
#Параметры пути
| Параметр | Тип | Описание |
|---|---|---|
id (path) |
UUID | Идентификатор приложения. |
versionId (path) |
string | Идентификатор версии вида v<N>. |
#Поля тела
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
tags |
string[] | нет | Новый полный список тегов. Заменяет существующие теги целиком. Если поле отсутствует — теги не изменяются. |
note |
string | null | нет | Комментарий. Строка — перезаписывает текущий. null — очищает комментарий. Если поле отсутствует — комментарий не изменяется. |
Можно передать только tags, только note или оба поля одновременно.
#Ответ
HTTP 200:
{
"success": true,
"data": {
"versionId": "v3",
"tags": ["manual"],
"note": "Финальная версия перед релизом"
}
}
#Примеры
#curl — добавить тег `manual`
curl -X PATCH https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources/v3 \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Content-Type: application/json" \
-d '{ "tags": ["manual"] }'
#curl — очистить комментарий
curl -X PATCH https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources/v3 \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Content-Type: application/json" \
-d '{ "note": null }'
#JavaScript
await fetch(
`https://vibecode.bitrix24.tech/v1/apps/${appId}/sources/v3`,
{
method: 'PATCH',
headers: {
'X-Api-Key': process.env.VIBE_APP_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ tags: ['manual'], note: 'Финальная версия' }),
},
)
#Коды ошибок
| HTTP | Код | Когда возвращается |
|---|---|---|
| 400 | INVALID_METADATA |
Тело не прошло валидацию (некорректные теги или типы полей). |
| 400 | INVALID_VERSION_ID |
Формат versionId не соответствует v<целое неотрицательное число>. |
| 403 | NOT_AUTHORIZED |
Только автор приложения, OAuth-ключ приложения или администратор портала могут управлять снапшотами. |
| 404 | APP_NOT_FOUND |
Приложение не существует, удалено или принадлежит другому порталу. |
| 404 | VERSION_NOT_FOUND |
Версия с таким versionId не существует или была удалена. |
#Список версий
GET /v1/apps/:id/sources
Возвращает все актуальные (не удалённые) версии в порядке убывания времени сохранения — самая свежая первой.
#Параметры пути
| Параметр | Тип | Описание |
|---|---|---|
id (path) |
UUID | Идентификатор приложения. |
#Ответ
HTTP 200:
{
"success": true,
"data": {
"totalVersions": 3,
"currentVersionId": "v3",
"totalSizeBytes": 552960,
"versions": [
{
"versionId": "v3",
"filename": "2026-05-21T10-15-30-000Z-v3.tar.gz",
"contentType": "application/gzip",
"timestamp": "2026-05-21T10:15:30.000Z",
"size": 184320,
"sha256": "a3f5d8b2c1e9f4...",
"tags": [],
"savedBy": {
"userId": "8f1a2b3c-...",
"session": "claude-session-2026-05-21"
},
"linkedDeployId": null,
"deployStatus": null,
"note": "Добавил OAuth-флоу"
},
{
"versionId": "v2",
"filename": "2026-05-20T18-02-11-000Z-v2-published.tar.gz",
"contentType": "application/gzip",
"timestamp": "2026-05-20T18:02:11.000Z",
"size": 184320,
"sha256": "9e7c4b2a1f8d3...",
"tags": ["published"],
"savedBy": {
"userId": "8f1a2b3c-...",
"session": null
},
"linkedDeployId": "publish:2026-05-20T18:05:42.000Z",
"deployStatus": "success",
"note": null
},
{
"versionId": "v1",
"filename": "2026-05-20T09-44-50-000Z-v1.tar.gz",
"contentType": "application/gzip",
"timestamp": "2026-05-20T09:44:50.000Z",
"size": 184320,
"sha256": "5a8d3e2f1c4b9...",
"tags": [],
"savedBy": { "userId": "8f1a2b3c-...", "session": null },
"linkedDeployId": null,
"deployStatus": null,
"note": null
}
]
}
}
#Поля ответа
| Поле | Тип | Описание |
|---|---|---|
data.totalVersions |
number | Общее количество актуальных версий. |
data.currentVersionId |
string | null | Идентификатор самой свежей версии (v<N>). null, если версий нет. |
data.totalSizeBytes |
number | Суммарный размер всех архивов в байтах. |
data.versions[].versionId |
string | Идентификатор версии вида v<N>. |
data.versions[].filename |
string | Имя файла в хранилище. Содержит суффикс -published или -manual, если есть соответствующий тег. |
data.versions[].contentType |
string | null | Тип архива (application/gzip, application/zip и т.д.). |
data.versions[].timestamp |
string | Время сохранения (ISO 8601, UTC). |
data.versions[].size |
number | Размер архива в байтах. |
data.versions[].sha256 |
string | SHA-256 содержимого архива. Используется для дедупликации. |
data.versions[].tags |
string[] | Активные теги: manual, published. |
data.versions[].savedBy.userId |
string | null | Идентификатор пользователя Вайбкод. |
data.versions[].savedBy.session |
string | null | Идентификатор AI-сессии (из заголовка X-AI-Session-Id). |
data.versions[].linkedDeployId |
string | null | Идентификатор публикации (заполняется после POST /v1/apps/:id/publish). |
data.versions[].deployStatus |
string | null | Статус публикации: success или failed. |
data.versions[].note |
string | null | Комментарий из поля X-Note при сохранении или из PATCH. |
#Примеры
#curl
curl -H "X-Api-Key: YOUR_APP_KEY" \
https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources
#JavaScript
const res = await fetch(
`https://vibecode.bitrix24.tech/v1/apps/${appId}/sources`,
{ headers: { 'X-Api-Key': process.env.VIBE_APP_KEY } },
)
const { data } = await res.json()
console.log(`Версий: ${data.totalVersions}, последняя: ${data.currentVersionId}`)
#Коды ошибок
| HTTP | Код | Когда возвращается |
|---|---|---|
| 403 | NOT_AUTHORIZED |
Только автор приложения, OAuth-ключ приложения или администратор портала могут управлять снапшотами. |
| 404 | APP_NOT_FOUND |
Приложение не существует, удалено или принадлежит другому порталу. |
#Скачивание архива
GET /v1/apps/:id/sources/:versionId/download
Возвращает подписанную ссылку на архив версии. Ссылка действует 30 минут.
#Параметры пути
| Параметр | Тип | Описание |
|---|---|---|
id (path) |
UUID | Идентификатор приложения. |
versionId (path) |
string | Идентификатор версии вида v<N>. |
#Ответ
HTTP 200:
{
"success": true,
"data": {
"url": "https://<storage-endpoint>/...",
"expiresAt": "2026-05-21T10:45:30.000Z"
}
}
#Примеры
#curl
# Получить ссылку
curl -H "X-Api-Key: YOUR_APP_KEY" \
https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources/v3/download
# Скачать архив по полученной ссылке (без дополнительных заголовков)
curl -o source-v3.tar.gz "<url из ответа выше>"
#JavaScript
const { data } = await fetch(
`https://vibecode.bitrix24.tech/v1/apps/${appId}/sources/v3/download`,
{ headers: { 'X-Api-Key': process.env.VIBE_APP_KEY } },
).then((r) => r.json())
const archive = await fetch(data.url)
const buffer = await archive.arrayBuffer()
// Дальше — распаковка архива (tar.gz: tar library; zip: JSZip или аналог)
#Коды ошибок
| HTTP | Код | Когда возвращается |
|---|---|---|
| 400 | INVALID_VERSION_ID |
Формат versionId не соответствует v<целое неотрицательное число>. |
| 403 | NOT_AUTHORIZED |
Только автор приложения, OAuth-ключ приложения или администратор портала могут управлять снапшотами. |
| 404 | APP_NOT_FOUND |
Приложение не существует, удалено или принадлежит другому порталу. |
| 404 | VERSION_NOT_FOUND |
Версия с таким versionId не существует или была удалена. |
| 502 | SOURCE_DOWNLOAD_URL_FAILED |
Хранилище временно недоступно — повторите запрос. |
#Постановка и снятие тега
POST /v1/apps/:id/sources/:versionId/tag
Распознаются два тега, оба защищают версию от автоматической очистки:
manual— версия закреплена оператором вручную.published— версия зафиксирована как опубликованная (этот тег также проставляется автоматически послеPOST /v1/apps/:id/publish).
#Параметры пути
| Параметр | Тип | Описание |
|---|---|---|
id (path) |
UUID | Идентификатор приложения. |
versionId (path) |
string | Идентификатор версии вида v<N>. |
#Поля тела
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
tag |
string | да | manual или published. |
action |
string | да | add — добавить тег, remove — снять. |
#Ответ
HTTP 200:
{
"success": true,
"data": {
"versionId": "v3",
"tags": ["manual"]
}
}
#Примеры
#curl
curl -X POST https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources/v3/tag \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Content-Type: application/json" \
-d '{ "tag": "manual", "action": "add" }'
#JavaScript
await fetch(
`https://vibecode.bitrix24.tech/v1/apps/${appId}/sources/v3/tag`,
{
method: 'POST',
headers: {
'X-Api-Key': process.env.VIBE_APP_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ tag: 'manual', action: 'add' }),
},
)
#Коды ошибок
| HTTP | Код | Когда возвращается |
|---|---|---|
| 400 | INVALID_TAG |
Тег не входит в набор manual, published. |
| 400 | INVALID_ACTION |
Действие не равно add или remove. |
| 400 | INVALID_VERSION_ID |
Формат versionId не соответствует v<целое неотрицательное число>. |
| 403 | NOT_AUTHORIZED |
Только автор приложения, OAuth-ключ приложения или администратор портала могут управлять снапшотами. |
| 404 | APP_NOT_FOUND |
Приложение не существует, удалено или принадлежит другому порталу. |
| 404 | VERSION_NOT_FOUND |
Версия с таким versionId не существует или была удалена. |
#Удаление версии
DELETE /v1/apps/:id/sources/:versionId
Помечает версию как удалённую. Восстановить версию через API нельзя. Версия с тегом published или manual защищена от удаления — сначала снимите тег через PATCH /v1/apps/:id/sources/:versionId с телом {"tags": []} (или с сохранением других тегов). Ответ включает hint.preservedTags — теги без защитных меток, которые стоит сохранить при снятии защиты.
#Параметры пути
| Параметр | Тип | Описание |
|---|---|---|
id (path) |
UUID | Идентификатор приложения. |
versionId (path) |
string | Идентификатор версии вида v<N>. |
#Ответ
HTTP 200:
{
"success": true,
"data": { "versionId": "v3" }
}
#Примеры
#curl
curl -X DELETE https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources/v3 \
-H "X-Api-Key: YOUR_APP_KEY"
#JavaScript
await fetch(
`https://vibecode.bitrix24.tech/v1/apps/${appId}/sources/v3`,
{
method: 'DELETE',
headers: { 'X-Api-Key': process.env.VIBE_APP_KEY },
},
)
#Коды ошибок
| HTTP | Код | Когда возвращается |
|---|---|---|
| 400 | INVALID_VERSION_ID |
Формат versionId не соответствует v<целое неотрицательное число>. |
| 403 | NOT_AUTHORIZED |
Только автор приложения, OAuth-ключ приложения или администратор портала могут управлять снапшотами. |
| 404 | APP_NOT_FOUND |
Приложение не существует, удалено или принадлежит другому порталу. |
| 404 | VERSION_NOT_FOUND |
Версия с таким versionId не существует или уже удалена. |
| 409 | PROTECTED_BY_TAG |
Версия отмечена тегом published или manual. Сначала снимите тег через PATCH /v1/apps/:id/sources/:versionId. |
#Массовая очистка
POST /v1/apps/:id/sources/cleanup
Удаляет старые версии, оставляя keepLatest самых свежих (по умолчанию — 5). Версии с тегами manual и published исключаются из очистки независимо от keepLatest.
#Параметры пути
| Параметр | Тип | Описание |
|---|---|---|
id (path) |
UUID | Идентификатор приложения. |
#Поля тела
| Поле | Тип | Обязательное | По умолчанию | Описание |
|---|---|---|---|---|
keepLatest |
number | нет | 5 |
Сколько последних версий оставить. Целое неотрицательное число. 0 оставит только версии с тегами manual и published. |
Тело можно опустить — применяется значение по умолчанию.
#Ответ
HTTP 200:
{
"success": true,
"data": {
"deletedVersions": ["v2", "v1"]
}
}
#Примеры
#curl
curl -X POST https://vibecode.bitrix24.tech/v1/apps/<APP_ID>/sources/cleanup \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Content-Type: application/json" \
-d '{ "keepLatest": 3 }'
#JavaScript
const res = await fetch(
`https://vibecode.bitrix24.tech/v1/apps/${appId}/sources/cleanup`,
{
method: 'POST',
headers: {
'X-Api-Key': process.env.VIBE_APP_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ keepLatest: 3 }),
},
)
const { data } = await res.json()
console.log('Удалено версий:', data.deletedVersions.length)
#Коды ошибок
| HTTP | Код | Когда возвращается |
|---|---|---|
| 400 | INVALID_KEEP_LATEST |
Значение keepLatest не является целым неотрицательным числом. |
| 403 | NOT_AUTHORIZED |
Только автор приложения, OAuth-ключ приложения или администратор портала могут управлять снапшотами. |
| 404 | APP_NOT_FOUND |
Приложение не существует, удалено или принадлежит другому порталу. |
#Деплой из снапшота
POST /v1/infra/servers/:id/deploy принимает поле source.versionId — альтернатива source.url и source.content. Позволяет развернуть на сервере ровно ту версию, которая была сохранена через save_sources, без отдельной загрузки файла.
{
"source": {
"versionId": "v3"
},
"start": "node server.js"
}
Сервер разрешает versionId в подписанную ссылку на архив и выполняет деплой. После успешного или неуспешного деплоя поле linkedDeployId у снапшота обновляется автоматически.
Ограничение: серверу должен соответствовать ключ авторизации приложения (vibe_app_*). Личные и менеджмент-ключи без привязанного appId не могут разрешить снапшот — вернётся 400 SOURCE_VERSION_REQUIRES_APP.
#Поведение перед публикацией
Описано выше в разделе «Гарантия наличия снапшота перед публикацией». Справочник кодов ошибок POST /v1/apps/:id/publish, специфичных для проверки снапшота:
| HTTP | Код | Когда возвращается |
|---|---|---|
| 409 | SNAPSHOT_REQUIRED |
Снапшота нет или он старше 10 минут (только при включённом сохранении). В ответе — поле hint с описанием действия. |
#Проверка состояния портала
GET /v1/me возвращает блок data.capabilities.apps.sourceStorage:
При включённом сохранении:
{
"capabilities": {
"apps": {
"sourceStorage": {
"enabled": true,
"requiredBeforeDeploy": false,
"automaticOnDeploy": true,
"freshnessWindowMinutes": 10,
"limits": {
"maxBlobBytes": 209715200
}
}
}
}
}
При отключённом сохранении:
{
"capabilities": {
"apps": {
"sourceStorage": {
"enabled": false,
"requiredBeforeDeploy": false,
"automaticOnDeploy": false,
"disabledBy": "platform",
"readOperations": "available",
"reactivation": {
"scope": "platform",
"permission": "platform admin"
}
}
}
}
}
Поле disabledBy — "platform" (функция не включена на уровне платформы) или "portal" (владелец портала отключил). Поле readOperations: "available" означает, что список версий и скачивание остаются доступными даже при отключённом сохранении. Блок reactivation указывает, на каком уровне (платформа или портал) включается функция и какие права для этого нужны.
#Отключение для портала
Владелец портала может отключить сохранение исходников через раздел администрирования (PATCH /api/admin/source-storage с телом { "sourceStorageEnabled": false }, требует сессии администратора). При отключении:
POST /v1/apps/:id/sourcesвозвращает200 { skipped: true, reason: "DISABLED_FOR_PORTAL" }.POST /v1/apps/:id/publishне проверяет наличие снапшота.GET /v1/apps/:id/sourcesпродолжает возвращать ранее сохранённые версии.GET /v1/apps/:id/sources/:versionId/downloadостаётся доступным.
История сохранений переживает повторное включение — ранее созданные версии остаются доступными.
#Поведение для AI-моделей
MCP-инструмент save_sources обёртывает POST /v1/apps/:id/sources. Инструмент load_sources скачивает и распаковывает последний снапшот в дерево файлов.
С 2026-05-23 явный вызов save_sources перед развёртыванием не требуется — платформа сохраняет байты автоматически. save_sources остаётся нужным только для трёх явных сценариев (раздел «Сохранение исходников» выше).
Каналы, через которые модель узнаёт о сохранении исходников:
- Описание MCP-инструментов
save_sourcesиload_sources— видно при первом обращении. - Подсказка в ответе
409 SNAPSHOT_REQUIRED(развёртывание с внешним URL) — предлагает загрузить черезPOST /sourcesили передатьX-Skip-Source-Snapshot. - Подсказка в ответе
409 SNAPSHOT_REQUIRED(публикация без свежего снапшота) — направляет в циклpublish → save_sources → publish(актуально, если источник — внешний URL и автосохранение было пропущено). - Блок
capabilities.apps.sourceStorageв ответеGET /v1/me— программная проверка состояния.