Для AI-агентов: markdown этой страницы — /docs-content/infra/deploy/operation-status.md индекс документации — /llms.txt
Исход выкладки
GET /v1/infra/operations/:operationId
Возвращает исход конкретной выкладки по её идентификатору. Нужен, когда соединение с POST /deploy оборвалось и терминальный ответ до клиента не дошёл: идентификатор выдаётся до начала работы, поэтому по нему можно узнать, чем всё кончилось, вместо того чтобы запускать выкладку заново.
Ручка только на чтение, побочных действий у неё нет. Каждая выкладка адресуется отдельно, включая предыдущие попытки на том же сервере. Исход хранится 7 суток.
Идентификатор выдаётся только при выкладке на отдельную виртуальную машину (kind: "STANDALONE"). У galaxy-приложения (kind: "GALAXY_APP") его нет, и сверить исход такой выкладки этой ручкой пока нельзя.
Где взять идентификатор — три канала, все три несёт одна и та же выкладка:
- заголовок ответа
X-Vibe-Operation-Id— приходит сразу, до начала долгой работы; - первый кадр
event: operationпри?stream=true— браузерныйEventSourceзаголовков ответа не отдаёт, поэтому для него это единственный доступный канал; - поле
operationIdв теле —data.operationIdпри успехе,error.operationIdпри отказе.
Отсутствие идентификатора не означает, что выкладка не запускалась. Если платформа не смогла завести запись, выкладка продолжается без идентификатора, а заголовка, кадра и поля не будет. Читать это как отказ и повторять выкладку нельзя — второй запуск ляжет поверх приложения, которое уже могло подняться.
Параметры
| Параметр | В | Тип | Обяз. | Описание |
|---|---|---|---|---|
operationId |
path | string | да | Идентификатор операции из ответа POST /deploy |
Примеры
curl — личный ключ
curl -H "X-Api-Key: YOUR_API_KEY" \
https://vibecode.bitrix24.tech/v1/infra/operations/OPERATION_ID
curl — OAuth-приложение
curl -H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
https://vibecode.bitrix24.tech/v1/infra/operations/OPERATION_ID
JavaScript — личный ключ
// Выкладка: забираем идентификатор из заголовка ДО того, как придёт тело
const deploy = await fetch(
`https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/deploy`,
{
method: 'POST',
headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ source: { content: archiveBase64 }, start: 'node index.js' }),
}
)
const operationId = deploy.headers.get('X-Vibe-Operation-Id')
// Связь оборвалась — спрашиваем исход вместо повторной выкладки
const res = await fetch(
`https://vibecode.bitrix24.tech/v1/infra/operations/${operationId}`,
{ headers: { 'X-Api-Key': 'YOUR_API_KEY' } }
)
if (res.status === 410) {
console.log('Операция была, исход больше не хранится')
} else if (res.status === 404) {
console.log('Такой операции нет')
} else {
const { data } = await res.json()
console.log(`Статус: ${data.status}, шаг: ${data.step}`)
}
JavaScript — OAuth-приложение
const res = await fetch(
`https://vibecode.bitrix24.tech/v1/infra/operations/${operationId}`,
{
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
}
)
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
success |
boolean | Всегда true при успехе |
data.operationId |
string | Идентификатор операции |
data.kind |
string | Вид операции. Сейчас всегда deploy |
data.serverId |
string | ID сервера, на котором шла выкладка |
data.status |
string | running, succeeded, failed или unknown — см. таблицу ниже |
data.step |
string | null | Шаг конвейера, на котором операция находится или на котором остановилась |
data.startedAt |
string | Время старта, ISO 8601 |
data.finishedAt |
string | null | Время завершения, ISO 8601. null, пока операция идёт |
data.error |
object | null | { code, message } при status: "failed", иначе null |
Значения data.status:
| Значение | Что означает |
|---|---|
running |
Выкладка идёт прямо сейчас |
succeeded |
Выкладка завершилась успешно |
failed |
Выкладка провалилась, причина — в data.error |
unknown |
Процесс прервался между стартом и записью исхода, поэтому исход неизвестен. Не то же самое, что «выкладки не было»: операция точно запускалась. Текущее состояние сервера смотрите в GET /v1/infra/servers/:id |
Пример ответа
Выкладка идёт:
{
"success": true,
"data": {
"operationId": "clz9k2m4x0001qw8h3f7d2n5p",
"kind": "deploy",
"serverId": "8f14e45f-ceea-467a-9c8d-2f1c5a6b7e30",
"status": "running",
"step": "install",
"startedAt": "2026-08-11T09:14:22.117Z",
"finishedAt": null,
"error": null
}
}
Выкладка завершилась успешно:
{
"success": true,
"data": {
"operationId": "clz9k2m4x0001qw8h3f7d2n5p",
"kind": "deploy",
"serverId": "8f14e45f-ceea-467a-9c8d-2f1c5a6b7e30",
"status": "succeeded",
"step": null,
"startedAt": "2026-08-11T09:14:22.117Z",
"finishedAt": "2026-08-11T09:18:04.902Z",
"error": null
}
}
Выкладка провалилась:
{
"success": true,
"data": {
"operationId": "clz9k2m4x0001qw8h3f7d2n5p",
"kind": "deploy",
"serverId": "8f14e45f-ceea-467a-9c8d-2f1c5a6b7e30",
"status": "failed",
"step": "healthcheck",
"startedAt": "2026-08-11T09:14:22.117Z",
"finishedAt": "2026-08-11T09:17:41.338Z",
"error": {
"code": "DEPLOY_STEP_FAILED",
"message": "connect ECONNREFUSED 127.0.0.1:3000"
}
}
}
Пример ответа при ошибке
410 — операция была, но исход уже не хранится:
{
"success": false,
"error": {
"code": "OPERATION_OUTCOME_EXPIRED",
"message": "The outcome of this deploy is no longer stored (kept for 7 days).",
"serverId": "8f14e45f-ceea-467a-9c8d-2f1c5a6b7e30",
"startedAt": "2026-07-30T11:02:19.400Z"
}
}
Ошибки
| HTTP | Код | Описание |
|---|---|---|
| 400 | INVALID_OPERATION_ID |
Идентификатор не той формы, которую выдаёт платформа |
| 401 | MISSING_API_KEY |
Не передан заголовок X-Api-Key |
| 401 | INVALID_API_KEY |
Неверный или просроченный API-ключ |
| 404 | OPERATION_NOT_FOUND |
Операции нет, она принадлежит другому ключу либо запись уже удалена |
| 410 | OPERATION_OUTCOME_EXPIRED |
Операция ваша, но её исход больше не хранится |
| 429 | RATE_LIMITED |
Превышен лимит опроса |
Полный список общих ошибок API — Ошибки.
Известные особенности
- Чужая операция отвечает так же, как несуществующая — это сделано намеренно. Все три случая (идентификатора нет, идентификатор чужой, запись удалена) дают один и тот же
404. Отдельный ответ на чужую операцию подтверждал бы, что такой идентификатор существует, а идентификатор сам по себе является ключом доступа к записи: подобрав его, можно было бы прочитать чужую выкладку. - 410 отличается от 404 только для владельца. «Исход больше не хранится» приходит, когда операция ваша и она точно была, просто прошло больше 7 суток. На чужой или выдуманный идентификатор такой ответ не приходит никогда.
- Запись живёт дольше, чем хранится исход. Через 7 суток исход перестаёт отдаваться, но сам факт операции сохраняется ещё некоторое время — за счёт этого и возможен различимый ответ
410. Потом запись удаляется, и тот же идентификатор начинает отвечать404. unknown— это ответ, а не ошибка. Он означает, что процесс выкладки прервался между стартом и записью исхода: операция точно была, но чем кончилась — платформа не знает. Смотрите текущее состояние сервера и, если приложение не поднялось, выкладывайте заново.- Лимит опроса — 60 запросов в минуту на ключ. Исход не меняется чаще, чем идёт сама выкладка, поэтому опрашивать раз в несколько секунд достаточно.