
## Принудительно освободить канал

`POST /v1/infra/servers/:id/unstick`

Принудительно освобождает канал выполнения команд на сервере: снимает серверную блокировку операций и разрывает туннель агента. Виртуальная машина при этом не перезагружается.

Это средство восстановления после отказа `409 EXEC_BUSY`, который приходит на [Выполнение команд](/docs/infra/deploy/exec) и на выкладку. Штатный порядок — сначала [Снять зависший лок](/docs/infra/deploy/lock), и только если `EXEC_BUSY` держится после этого, звать принудительное освобождение.

## Параметры

| Параметр | В | Тип | Обяз. | По умолч. | Описание |
|----------|---|-----|:-----:|-----------|----------|
| `id` | path | string (UUID) | да | — | ID сервера вида `STANDALONE`. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) |
| `force` | query | string | нет | — | `true` или `1` — освободить канал даже тогда, когда на сервере идёт настоящая операция: она при этом прерывается. Без параметра такой вызов отклоняется с `409 OPERATION_IN_PROGRESS` и операция продолжается |

Тело запроса пустое.

## Примеры

### curl — личный ключ

```bash
curl -X POST -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/unstick
```

### curl — OAuth-приложение

```bash
curl -X POST -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/unstick
```

### JavaScript — личный ключ

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/unstick`,
  { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' } }
)
const body = await res.json()
if (!body.success) {
  console.error(body.error.code, body.error.message)
} else if (!body.data.reconnected) {
  console.log('Агент ещё переподключается — повторите команду через несколько секунд')
}
```

### JavaScript — OAuth-приложение

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/unstick`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  }
)
```

Освобождение поверх идущей операции — тот же запрос с `?force=true` в строке запроса.

## Поля ответа

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | `true` при успешном освобождении канала |
| `data.backendLockReleased` | boolean | Серверная блокировка операций снята |
| `data.agentBounced` | boolean | Туннель агента разорван. `false`, когда разрывать было нечего — агент не был подключён либо сервер спит |
| `data.reconnected` | boolean | Агент подтверждённо переподключился за отведённое окно ожидания. `false` — ожидание истекло, а не отказ |

## Пример ответа

```json
{
  "success": true,
  "data": {
    "backendLockReleased": true,
    "agentBounced": true,
    "reconnected": true
  }
}
```

## Пример ответа при ошибке

404 — сервер не найден:

```json
{
  "success": false,
  "error": {
    "code": "SERVER_NOT_FOUND",
    "message": "Server not found"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ |
| 403 | `INFRA_FORBIDDEN_FOR_COWORK_KEY` | Вызов сделан ключом Cowork/Code — такой ключ работает только с данными, изменяющие операции ему закрыты. Что делать — [Проектный ключ для деплоя](/docs/cowork/deploy-key) |
| 404 | `SERVER_NOT_FOUND` | Сервер не существует, удалён или принадлежит другому API-ключу. Тот же код приходит, если запись сервера исчезла между проверкой доступа и освобождением канала. Членство в команде разработки сервера эту операцию не открывает — она требует управляющего ключа при любой роли. |
| 409 | `OPERATION_IN_PROGRESS` | На сервере идёт настоящая операция — выкладка, выполнение команды, усиление защиты или смена режима. Канал не завис, поэтому вызов отклонён, а операция продолжается. Имя операции — в `message`. Повторите с `force=true`, только если уверены, что канал действительно завис |
| 409 | `CONFLICT` | Освобождение канала на этом сервере уже идёт — дождитесь его окончания и повторите |
| 409 | `GALAXY_UNSTICK_UNSUPPORTED` | Сервер вида `GALAXY` или `GALAXY_APP`: канал выполнения команд общий для всех приложений хоста, и его разрыв оборвал бы команды соседей. При устойчивой занятости обращайтесь в поддержку: общий хост освобождает платформенная команда |
| 429 | `RATE_LIMITED` | Превышен лимит 6 запросов в минуту на пару «API-ключ + сервер» |
| 502 | `GATEWAY_ERROR` | Серверная блокировка снята, но туннель агента разорвать не удалось — Gateway недоступен. Восстановление неполное, повторите запрос |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Известные особенности

- **Что происходит с зависшей командой.** Разрыв туннеля заставляет агента завершить процесс-группу зависшей команды и подключиться заново. Сервис приложения при этом не перезапускается, файлы на диске не меняются, переустановки агента не происходит — в отличие от [Восстановить туннель](/docs/infra/lifecycle/repair), который переустанавливает агента целиком.
- **Освобождение канала не будит спящий сервер.** Если сервер в статусе `sleeping` или у него стоит запрет пробуждения, туннеля нет и разрывать нечего: платформа снимает серверную блокировку и отвечает успехом с `agentBounced: false`.
- **Окно ожидания переподключения короткое и не влияет на исход.** Платформа наблюдает за туннелем несколько секунд после разрыва и отвечает, не дожидаясь дольше. Агент подключается сам, поэтому `reconnected: false` означает «ещё не увидели», а не «не вернулся» — повторите нужную команду через несколько секунд.

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

- [Выполнение команд](/docs/infra/deploy/exec)
- [Снять зависший лок](/docs/infra/deploy/lock)
- [Восстановить туннель](/docs/infra/lifecycle/repair)
- [Полный деплой](/docs/infra/deploy/deploy)
