Для AI-агентов: markdown этой страницы — /docs-content/apps/publish.md индекс документации — /llms.txt
Опубликовать приложение
POST /v1/apps/:id/publish
Переводит приложение в PUBLISHED, привязывает места встраивания к порталу и делает приложение видимым всем сотрудникам.
Параметры
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
id (path) |
string | да | Идентификатор приложения. Список: GET /v1/apps |
Поля запроса (body)
Тело необязательное. При пустом теле берутся значения из записи приложения — это основной сценарий повторной публикации без изменений. Если передаёте тело, добавьте заголовок Content-Type: application/json — без него запрос с телом вернёт 413 PAYLOAD_TOO_LARGE.
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
catalogTitle |
string | нет | Название в каталоге портала, не только из пробелов. Если не передано — текущее значение приложения |
catalogDescription |
string | нет | Описание в каталоге |
catalogIcon |
string | нет | Код иконки в каталоге |
appUrl |
string | нет | Адрес приложения: сервер Black Hole, контейнер в галактике или внешний https-адрес. Если не передан — текущий appUrl приложения |
placements |
string[] | нет | Коды мест встраивания. Список допустимых кодов — Доступные места. Если не передан — текущий набор приложения |
sourceVersionId |
string | нет | Конкретный снапшот исходников для публикации, формат v<номер>. Применимо при включённом хранилище исходников |
sourceServerId |
string | нет | Сервер, исходники которого публикуются, — идентификатор из POST /v1/infra/servers/:id/deploy. Нужен, когда исходники сохранил автосейв деплоя на сервере, который не принадлежит OAuth-ключу этого приложения: такой снапшот хранится у сервера, а не у приложения. Тот же смысл у заголовка X-Source-Server. Платформа сервер не подбирает — без этого поля проверка ищет снапшот приложения. Применимо при включённом хранилище исходников |
Примеры
curl — личный ключ
curl -X POST "https://vibecode.bitrix24.tech/v1/apps/YOUR_APP_ID/publish" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "placements": ["CRM_DEAL_DETAIL_TAB"] }'
curl — OAuth-приложение
curl -X POST "https://vibecode.bitrix24.tech/v1/apps/YOUR_APP_ID/publish" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "placements": ["CRM_DEAL_DETAIL_TAB"] }'
JavaScript — личный ключ
const res = await fetch(
'https://vibecode.bitrix24.tech/v1/apps/YOUR_APP_ID/publish',
{
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ placements: ['CRM_DEAL_DETAIL_TAB'] }),
}
)
const body = await res.json()
if (!body.success) throw new Error(body.error.code)
// body.warnings — нефатальные пояснения; отказ привязки возвращает PLACEMENT_BIND_FAILED
console.log(body.data.placements)
JavaScript — OAuth-приложение
const res = await fetch(
'https://vibecode.bitrix24.tech/v1/apps/YOUR_APP_ID/publish',
{
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({ placements: ['CRM_DEAL_DETAIL_TAB'] }),
}
)
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
success |
boolean | true при успешной публикации |
data |
object | Приложение после публикации — тот же набор полей, что отдаёт данные приложения |
data.placements |
string[] | Привязанные места встраивания |
data.catalogStatus |
string | После публикации — PUBLISHED |
data.publishedAt |
string | null | Дата публикации, ISO 8601 |
warnings |
string[] | Предупреждения, не отменяющие публикацию. Про снятие лишних мест строка приходит по-разному в зависимости от раскатки — разбор во врезке под таблицей ошибок. Переданный sourceServerId не был использован, потому что хранилище исходников для портала отключено. Опубликованная версия сервера осталась без бессрочного хранения — тогда строка несёт готовый PATCH, которым её можно пометить. Название или описание карточки потеряли не-ASCII символы по дороге — строка называет поле. Набор строк открытый: незнакомую строку показывайте как есть, а не отбрасывайте |
Пример ответа
Поле data повторяет объект приложения с заполненным массивом placements:
{
"success": true,
"data": {
"id": "33c4d5e6-f7a8-49b0-1234-5c6d7e8f9012",
"title": "Дашборд продаж",
"description": null,
"scopes": ["crm", "user", "placement"],
"handlerUrl": "https://vibecode.bitrix24.tech/v1/bitrix-handler",
"appUrl": "https://app-abc12345.vibecode.bitrix24.tech",
"redirectUris": [
"https://vibecode.bitrix24.tech/oauth/complete",
"http://localhost"
],
"bitrixClientId": "local.7c3d4e5f6a7b80.55556666",
"prefix": "vibe_app_local_7c3",
"suffix": "6666",
"authorId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"authorBitrixUserId": 42,
"authorBitrixUserIdSource": "member",
"portalId": "8b1f0e2a-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
"createdAt": "2026-06-24T09:12:45.781Z",
"updatedAt": "2026-06-24T10:03:18.204Z",
"placements": ["CRM_DEAL_DETAIL_TAB"],
"catalogStatus": "PUBLISHED",
"publishedAt": "2026-06-24T10:03:18.204Z"
}
}
Пример ответа при ошибке
400 — у OAuth-ключа нет скоупа placement:
{
"success": false,
"error": {
"code": "MISSING_SCOPE",
"message": "OAuth API key must have the placement scope to publish (catalog publishing binds placements on Bitrix24)."
}
}
Ошибки
| HTTP | Код | Описание |
|---|---|---|
| 403 | INFRA_FORBIDDEN_FOR_COWORK_KEY |
Вызов сделан ключом Cowork/Code — такой ключ работает только с данными, изменяющие операции ему закрыты. Что делать — Проектный ключ для деплоя |
| 404 | NOT_FOUND |
Приложение не найдено или принадлежит другому порталу |
| 403 | FORBIDDEN |
Вызов сделан ключом авторизации vibe_app_…, выписанным на другое приложение. Таким ключом публикуют только своё приложение, даже если оба приложения создал один автор |
| 403 | FORBIDDEN |
Запрос не от автора приложения и не от администратора портала |
| 403 | WRITE_BLOCKED_READONLY_KEY |
Ключ не меняет данные Битрикс24, а приложение для него не своё. Своим считается приложение, созданное этим же ключом, для ключей места Коворка — любым ключом того же места, для ключа авторизации — его собственное приложение. Приложение, созданное в кабинете, такому ключу не своё |
| 403 | WRITE_BLOCKED_READONLY_KEY |
Ключ не меняет данные Битрикс24, а публикация затрагивает место в рабочем экране сотрудников или места на обработчике, который не является обработчиком платформы. Затронутыми считаются и добавляемые, и снимаемые места: placements: [] у приложения с привязанным местом в рабочем экране тоже отказывает. Пункт левого меню на обработчике платформы публикуется и снимается без отказа |
| 403 | WRITE_BLOCKED_READONLY_KEY |
Ключ не меняет данные Битрикс24, а тело несёт appUrl, хотя у приложения есть ключ с правом записи в Битрикс24 в любом статусе или нет ни одного ключа |
| 409 | ALREADY_PUBLISHED |
Приложение уже в статусе PUBLISHED |
| 400 | VALIDATION_ERROR |
Поле тела не прошло проверку — в message перечислены поля и причины отказа |
| 400 | VALIDATION_ERROR |
Заголовок X-Source-Server передан больше одного раза. Передавайте его один раз с одним идентификатором сервера |
| 400 | VALIDATION_ERROR |
Значение заголовка X-Source-Server не является идентификатором сервера в форме UUID |
| 400 | NO_OAUTH_KEY |
У приложения нет связанного OAuth-ключа |
| 400 | MISSING_SCOPE |
У OAuth-ключа нет скоупа placement |
| 409 | SNAPSHOT_REQUIRED |
Включено хранилище исходников, но сохранённого снапшота нет. Возраст снапшота на исход проверки не влияет. Тело несёт hint: без sourceServerId он ведёт на POST /v1/apps/:id/sources и объясняет, как опубликовать исходники с сервера. С sourceServerId — на POST /v1/infra/servers/:id/sources. Поле hint.reason различает две причины отказа — снапшота нет у приложения или у названного сервера. Ещё два значения приходят, только когда платформа проверяет возраст снапшота. Состав полей подсказки описан в Хранилище исходников |
| 404 | SERVER_NOT_FOUND |
Передан sourceServerId сервера, которого нет, который принадлежит другому порталу или который удалён |
| 403 | NOT_AUTHORIZED |
Передан sourceServerId сервера, исходники которого запрос не вправе использовать. Права на приложение сюда не распространяются — запрос должен идти от ключа-владельца сервера, личного ключа того же пользователя или администратора портала |
| 400 | NO_USER_TOKEN |
Приложение не авторизовано на портале по OAuth. Пройдите авторизацию и повторите публикацию — Авторизация пользователей приложения. Тело несёт hint из трёх полей: requiredAction — что сделать, docsUrl — эта страница, oauthDocsUrl — порядок авторизации. Набор полей у этой подсказки свой, он не совпадает с подсказкой SNAPSHOT_REQUIRED |
| 400 | TITLE_TOO_LONG_FOR_CATALOG |
Итоговое название длиннее 100 символов. Так бывает, когда catalogTitle не передан, а title приложения длиннее предела каталога |
| 400 | APP_URL_UNSAFE |
Адрес вне платформы должен быть публичным https://: без http://, без localhost и адресов внутренней сети и без логина и пароля в адресе |
| 403 | EXTERNAL_URL_ACTOR_NOT_ALLOWED |
Приложение с адресом, который не обслуживает действующий сервер этого портала на платформе (внешний хост или домен, чей сервер удалён), нельзя опубликовать ключом приложения, ключом Connect-партнёра, ключом, привязанным к серверу, ключом Коворка, ключом с назначением, управляющим ключом, рабочим ключом агента или управляемого бота. Используйте кабинет платформы Вайбкод или личный ключ |
| 403 | EXTERNAL_URL_DISABLED |
Публикация приложений с адресом вне платформы недоступна для этого аккаунта Битрикс24 |
| 409 | APP_URL_CONFLICT |
Адрес или статус приложения изменились параллельно. Перечитайте приложение и повторите запрос |
| 502 | PLACEMENT_UNBIND_FAILED |
Аккаунт не подтвердил снятие лишних мест встраивания. Приложение НЕ опубликовано, метаданные каталога из этого запроса не сохранены. Коды, которые остались на аккаунте, перечислены в error.placements. Поле placements приложения при этом уже перезаписано — перечитайте приложение. Приходит только после включения проверки — см. врезку ниже |
| 502 | PLACEMENT_BIND_FAILED |
Аккаунт не подтвердил одну или несколько запрошенных привязок. Приложение НЕ опубликовано. Уникальный список неподтверждённых привязок приходит в error.placements, а безопасные код и статус Битрикс24 для каждой попытки транспорта — в error.failures. Неподтверждённые снятия того же запроса приходят отдельно в error.failedUnbinds. Исходный текст ответа и адрес ключа разработчика не возвращаются. Поле placements уже содержит успешно привязанную часть — перечитайте приложение перед повтором |
| 503 | NETWORK_DEVKEY_REQUIRED |
Аккаунт переведён на транспорт ключа разработчика, а у автора приложения такого ключа нет. Повтор не поможет — попросите автора переподключить аккаунт. Приходит только после включения проверки — см. врезку ниже |
Полный список общих ошибок API — Ошибки.
Поля отказа `PLACEMENT_BIND_FAILED`
| Поле | Тип | Описание |
|---|---|---|
error.placements |
string[] | Уникальный список мест, чью привязку не подтвердил ни один транспорт |
error.failures |
object[] | По одной записи на каждую отклонённую попытку транспорта; порядок записей не является контрактом |
error.failures[].placement |
string | Код места встраивания из запроса |
error.failures[].transport |
string | Канал отклонённой попытки: developer_key или oauth |
error.failures[].bitrixCode |
string | Безопасный диагностический код Битрикс24, а не стабильный enum для клиентского ветвления. Решение об OAuth fallback платформа уже приняла до ответа; сохраняйте значение для диагностики и ориентируйтесь на внешний error.code |
error.failures[].bitrixStatus |
number | HTTP-статус ответа Битрикс24; 0, если транспорт не сообщил статус |
error.failedUnbinds |
string[] | Необязательный список старых мест, снятие которых не подтверждено в том же запросе |
Проверка снятия лишних мест встраивания на стороне аккаунта сейчас раскатывается по аккаунтам, поэтому вариантов два:
- Пока возможность не включена на аккаунте — публикация отвечает
200, даже если снять лишние места на аккаунте не удалось. Неснятый код при этом ОСТАЁТСЯ вplacementsприложения, а причина приходит строкойFailed to unbind <код>вwarnings. Это единственный признак расхождения списка с аккаунтом, поэтому сейчасwarningsнадо разбирать. КодовPLACEMENT_UNBIND_FAILEDиNETWORK_DEVKEY_REQUIREDу этого эндпоинта не бывает. - После включения — неподтверждённое снятие отвечает
502 PLACEMENT_UNBIND_FAILEDсо списком кодов вerror.placements, а приложение не публикуется вовсе. Ответа200с неснятым местом на этом пути не бывает — про снятие вwarningsуспешного ответа остаются пояснения о подтверждении: каким транспортом снятие подтверждено и отказал ли при этом второй.
Отказ запрошенной привязки не зависит от этого флага: на обеих сторонах раскатки он отвечает 502 PLACEMENT_BIND_FAILED и не переводит приложение в PUBLISHED. Если в том же запросе не подтверждено и снятие старого места, внешний код всё равно остаётся PLACEMENT_BIND_FAILED, а старое место попадает в error.failedUnbinds. Если ключ разработчика отклонён с HTTP 401 только из-за учётных данных, а у приложения есть OAuth-токен, публикация сначала повторяет привязку по OAuth; успешный отход остаётся ответом 200 и фиксируется в аудите. Явная неавторизационная причина — например, подписочный гейт или нехватка прав — остаётся окончательной при любом HTTP-статусе и никогда не повторяется по OAuth.
Отказ 502 здесь не означает «ничего не изменилось». Поле placements приложения записывается ДО того, как выносится отказ, и уже отражает фактическое состояние аккаунта: успешно снятые коды из него ушли, а неподтверждённые остались. Поэтому перед повтором перечитайте приложение через данные приложения. Повторный запрос без поля placements опубликует ровно тот набор, который лежит в приложении сейчас, — вместе с местом, которое вы считали снятым. Чтобы снять его, повторите запрос с явным placements без этого кода.
Известные особенности
- OAuth-авторизация даёт основной или резервный транспорт. На аккаунте без ключа разработчика привязку выполняет OAuth-токен. Если выбран ключ разработчика и Битрикс24 отклоняет его с HTTP 401 только из-за учётных данных, тот же OAuth-токен становится резервным каналом. Явные коды подписочного гейта окончательны при любом HTTP-статусе и в этот fallback не попадают. Без доступного транспорта публикация возвращает
NO_USER_TOKENилиNETWORK_DEVKEY_REQUIRED. Порядок авторизации — Авторизация пользователей приложения. - Вход на странице самого приложения токен приложения не создаёт. Кнопка «Войти через Bitrix24» на адресе вашего приложения выдаёт доступ к приложению — это другая поверхность, и на
NO_USER_TOKENпри публикации она не влияет. Токен появляется только на согласии OAuth на стороне портала: авторизация по ссылке выше, установка приложения на портал или первое открытие встроенного места. Если после входа на странице приложения публикация всё ещё отвечаетNO_USER_TOKEN— авторизации на портале не было. - Токен живёт долго и продлевается сам. Авторизация нужна один раз, а не перед каждой публикацией: платформа обновляет токен по refresh-токену. Повторная авторизация требуется, только если доступ отозвали на портале или OAuth-приложение пересоздали.
autoSaved: trueу деплоя не всегда закрывает проверку публикации. Автосейв деплоя сохраняет исходники у того сервера, на который вы деплоили. Если этот сервер принадлежит не OAuth-ключу публикуемого приложения (например, вы деплоили личным ключомvibe_api_), снапшот хранится у сервера — проверка публикации по умолчанию смотрит снапшоты приложения и его не видит. ПередайтеsourceServerIdтого же сервера, и публикация возьмёт исходники оттуда — повторно сохранять их черезPOST /v1/apps/:id/sourcesне нужно. Идентификатор сервера — тот же, что в адресе деплоя. Список снапшотов сервера —GET /v1/infra/servers/:serverId/sources.- Заголовок места встраивания — это название приложения. Пункт левого меню и вкладки CRM подписываются итоговым
catalogTitle, отдельного названия для меню нет. Переименование приложения через обновление меняет и подписи мест встраивания. - Пункт левого меню у приложения уже есть. Приложение появляется в меню аккаунта сразу после создания, без публикации и без мест встраивания. Место
LEFT_MENUдобавляет к нему второй пункт меню со своим адресом на аккаунте. В Вайбкод приложение при этом одно, и привязанные места показывают одну записьLEFT_MENU. Если второй пункт не нужен, не передавайтеLEFT_MENUвplacements. У опубликованного приложения лишний пункт снимается отвязкой кодаLEFT_MENUили обновлением сplacementsбез этого кода. Пункт, появившийся при создании, при этом остаётся. - Снятые с публикации приложения публикуются повторно. Публикация принимается и в статусе
UNPUBLISHED— приложение возвращается вPUBLISHEDс теми же или новыми местами встраивания. Метаданные каталога при снятии с публикации сохранялись, поэтому при пустом теле каталог восстанавливается без повторного заполнения. - Каждое запрошенное место должно привязаться. Коды привязываются отдельно, поэтому часть из них может успеть записаться на аккаунте. Если хотя бы одна привязка не подтверждена, публикация отвечает
502 PLACEMENT_BIND_FAILED, приложение не становитсяPUBLISHED, а успешно привязанные коды уже остаются в его полеplacements.