## Последние операции сервера

`GET /v1/infra/servers/:id/operations`

Возвращает последние операции выкладки на сервере от текущего API-ключа, от новых к старым. Это канал восстановления, когда ответ [`POST /deploy`](./deploy.md) потерян раньше, чем клиент успел получить `operationId` — в частности, при обрыве связи во время сборки galaxy-приложения.

Ручка только читает общую запись исхода: она не будит сервер, не чинит туннель и не снимает mutex. Право на сервер совпадает с правом на deploy, но строки дополнительно фильтруются по точному API-ключу, который начал операцию. Поэтому связанный с приложением ключ может читать только собственные запуски, а id общего galaxy-хоста не даёт доступа к запускам его приложений. Владелец может сверить свои операции после мягкого удаления сервера.

## Параметры

| Параметр | В | Тип | Обяз. | Описание |
|----------|---|-----|:-----:|----------|
| `id` | path | string | да | ID сервера или galaxy-приложения |
| `limit` | query | integer | нет | Число строк: по умолчанию 5, максимум 20. Ноль ограничивается до 1, целое значение выше 20 — до 20; отрицательное, дробное или нечисловое значение даёт `400 INVALID_LIMIT` |

## Пример

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  'https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/operations?limit=5'
```

```json
{
  "success": true,
  "data": {
    "operations": [
      {
        "operationId": "clz9k2m4x0001qw8h3f7d2n5p",
        "serverId": "8f14e45f-ceea-467a-9c8d-2f1c5a6b7e30",
        "status": "running",
        "outcomeAvailable": true,
        "step": "build",
        "startedAt": "2026-08-26T09:14:22.117Z",
        "finishedAt": null,
        "error": null
      }
    ]
  }
}
```

## Поля операции

| Поле | Тип | Описание |
|------|-----|----------|
| `operationId` | string | Идентификатор для [`GET /v1/infra/operations/:operationId`](./operation-status.md) |
| `serverId` | string | ID сервера или galaxy-приложения |
| `outcomeAvailable` | boolean | Хранится ли исход операции |
| `status` | string | `running`, `succeeded`, `failed` или `unknown`; отсутствует у просроченного терминального исхода |
| `step` | string \| null | Последний наблюдаемый шаг; отсутствует у просроченного терминального исхода |
| `startedAt` | string | Время старта, ISO 8601 |
| `finishedAt` | string \| null | Время завершения; отсутствует у просроченного терминального исхода |
| `error` | object \| null | `{ code, message }` только для `failed`; отсутствует у просроченного терминального исхода |

Терминальный исход хранится 7 суток. После этого строка некоторое время остаётся в списке с `outcomeAvailable: false`, но её статус, шаг и ошибка больше не раскрываются. `unknown` — устойчивый терминальный ответ, когда платформа не может доказать удалённый исход, например после `GATEWAY_UNREACHABLE`; просроченная операция, оставшаяся в `running`, также отображается как `unknown`.

## Безопасное восстановление после обрыва

1. Не повторяйте deploy вслепую. Найдите свежую операцию этого ключа в списке.
2. Пока она `running`, ждите и опрашивайте список или адресную ручку раз в несколько секунд.
3. При `succeeded` или `failed` используйте подтверждённый исход. При `unknown` либо отсутствии записи сверьте [`GET /v1/infra/servers/:id`](/docs/infra/servers/get) и [логи](./logs.md).
4. Если следующий запрос подтвердил `EXEC_BUSY`, сначала убедитесь, что в списке уже нет `running`, затем учитывайте вид сервера. Для `STANDALONE` можно вызвать `POST /v1/infra/servers/:id/unstick` и снова выполнить read-only проверки. У `GALAXY_APP` exec-канал принадлежит общему хосту: tenant-вызов `unstick` не поддерживается; подождите 30–60 секунд, а при устойчивом `EXEC_BUSY` обратитесь в поддержку. После любого recovery снова сверьте список, состояние и логи до повторной выкладки.

Ответ standalone-deploy с транспортной причиной `GATEWAY_UNREACHABLE`, `DEPLOY_CONNECTION_TERMINATED`, `DEPLOY_TIMEOUT` или `DEPLOY_TUNNEL_STALE`, а также post-drop ответы Galaxy `GALAXY_DEPLOY_INTERRUPTED` и `GALAXY_HOST_UNREACHABLE`, содержат эту read-first последовательность в `error.hint`. У Galaxy такой ответ несёт `error.retryable: false`: сам по себе обрыв не доказывает ни успех, ни провал операции. Слот, контейнер и `/data` при неизвестном исходе сохранены — не удаляйте и не пересоздавайте приложение.

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `INVALID_LIMIT` | `limit` отрицательный, дробный, нечисловой или не помещается в безопасное целое число |
| 401 | `MISSING_API_KEY`, `INVALID_API_KEY` | Ключ отсутствует либо недействителен |
| 404 | `SERVER_NOT_FOUND` | Сервер недоступен этому ключу |
| 429 | `RATE_LIMITED` | Превышен лимит 60 запросов в минуту на ключ |

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

- [Исход по идентификатору](./operation-status.md)
- [Выложить приложение](./deploy.md)
- [Логи приложения](./logs.md)
