
## Unstick the channel

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

Recovers a stuck synchronous command channel on the server: releases the server-side operation lock and bounces the agent tunnel. The virtual machine is not rebooted.

Use this recovery for a confirmed leaked synchronous exec mutex after independently confirming the server is idle. Before acting on `EXEC_BUSY`, read the [server operations](/docs/infra/deploy/operations) with `kind=exec` and their [outcomes](/docs/infra/deploy/operation-status). This endpoint does not cancel independent standalone durable jobs or clear their admission gate, even with `force=true`. For a confirmed synchronous leak, respect `Retry-After` when present, then use this guarded endpoint; unconditional [lock deletion](/docs/infra/deploy/lock) comes last, after the idle-state check. On `STANDALONE`, a running durable job keeps the execution channel busy after `202` releases the platform lock. Poll its operation; an unknown outcome needs support and independently confirmed full termination. Missing `autoExpiresInSeconds` does not prove a leaked mutex. Tunnel recovery and lock deletion do not clear durable admission. Galaxy commands run synchronously with a 600-second limit and share the host channel across all applications and deploys; your own operation list may not show another application’s job, so an empty list does not prove the host is idle.

## Parameters

| Parameter | In | Type | Required | Default | Description |
|----------|---|-----|:-----:|-----------|----------|
| `id` | path | string (UUID) | yes | — | ID of a `STANDALONE` server. List: [`GET /v1/infra/servers`](/docs/infra/servers/list) |
| `force` | query | string | no | — | `true` or `1` — unstick even when an operation lock is detected or the lock check is unavailable. This can interrupt a running operation. Without the parameter, a detected lock returns `409 OPERATION_IN_PROGRESS`; an unavailable check returns `503 LOCK_STATE_UNAVAILABLE` |

The request body is empty.

## Examples

### curl — personal key

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

### curl — OAuth application

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

### JavaScript — personal key

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/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('The agent is still reconnecting — read the previous operation before retrying')
}
```

### JavaScript — OAuth application

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

To override the operation-lock guard, send the same request with `?force=true` in the query string. This can interrupt synchronous execution; it does not cancel an independent standalone durable job or clear its admission gate.

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` when the channel was freed |
| `data.backendLockReleased` | boolean | The server-side operation lock was released |
| `data.agentBounced` | boolean | The agent tunnel was bounced. `false` when there was nothing to bounce — the agent was not connected, or the server is asleep |
| `data.reconnected` | boolean | The agent was confirmed to have reconnected within the wait window. `false` means the wait window expired, not that the reconnect failed |

## Response example

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

## Error response example

404 — the server was not found:

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

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not provided |
| 401 | `INVALID_API_KEY` | The key is not recognized — no such key exists on the platform |
| 403 | `INFRA_FORBIDDEN_FOR_COWORK_KEY` | The call was made with a Cowork key — such a key works with data only and cannot perform write operations. To issue a key that can, see [Project key for deploy](/docs/cowork/deploy-key) |
| 404 | `SERVER_NOT_FOUND` | The server does not exist, was deleted, or belongs to a different API key. Being on the server's development team does not grant access to this operation — it requires the managing key regardless of your role. The same code is returned if the server record disappears between the access check and the channel reset. |
| 409 | `OPERATION_IN_PROGRESS` | An operation lock was detected. The channel was not reset. If the operation type is known, it is included in `message`. A held lock does not establish that the command is healthy. Retry with `force=true` only if you intend to interrupt the operation |
| 409 | `CONFLICT` | An unstick is already in progress for this server — wait for it to finish and retry |
| 409 | `GALAXY_UNSTICK_UNSUPPORTED` | A server of kind `GALAXY` or `GALAXY_APP`: the command execution channel is shared by every application on the host, and bouncing it would abort the neighbours' commands. If the busy state persists, contact support: releasing a shared host is a platform-team action |
| 429 | `RATE_LIMITED` | The limit of 6 requests per minute per "API key + server" pair was exceeded. The current limit is returned in the `x-ratelimit-limit` header |
| 502 | `GATEWAY_ERROR` | The server-side lock was released, but the agent tunnel could not be bounced — the Gateway is unreachable. Recovery is incomplete — retry the request |
| 503 | `LOCK_STATE_UNAVAILABLE` | The operation lock could not be checked. No server-side lock release or tunnel bounce was attempted. Retry later |

For the full list of common API errors, see [Errors](/docs/errors).

## Known specifics

- **The lock check observes the current state.** A shared operation lock normally blocks the request. However, if the lock holder record has exceeded its TTL and belongs to a command (`op: exec`), the request proceeds: the channel is reset, the tunnel is bounced, and the response is `200`. An expired lock holder record for a deploy still blocks the request because a legitimate deploy can outlive its TTL. The check does not reserve the channel: an operation may start afterwards, and some operations may run without a shared lock when the database is unavailable. Absence of a refusal does not guarantee that no commands are running.

- **What happens to the stuck synchronous command.** Bouncing the tunnel makes the agent terminate the stuck synchronous command's process group and connect again. The application service is not restarted, the files on disk are untouched, and the agent is not reinstalled — unlike [Repair the tunnel](/docs/infra/lifecycle/repair), which reinstalls the agent outright. Standalone durable jobs run independently; reconnecting does not prove they stopped or clear their admission gate.
- **Unsticking does not wake a sleeping server.** If the server is in `sleeping` status or waking is blocked for it, there is no tunnel and nothing to bounce: the platform releases the server-side lock and answers with success and `agentBounced: false`.
- **The reconnect wait window is short and does not change the outcome.** The platform watches the tunnel for a few seconds after the bounce and answers without waiting any longer. The agent reconnects on its own, so `reconnected: false` means "not seen yet" rather than "did not come back" — read the previous operation outcome before deciding whether to retry.

## See also

- [Run a command](/docs/infra/deploy/exec)
- [Release a stuck lock](/docs/infra/deploy/lock)
- [Repair the tunnel](/docs/infra/lifecycle/repair)
- [Full application deploy](/docs/infra/deploy/deploy)
