
## Wake server

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

Wakes a server from `sleeping` or `provisioning`. Unlike [`/start`](./start.md), `/wake` supports a blocking mode via `?wait=true` — the response is returned only when the server is fully ready (the virtual machine has started **and** the tunnel has connected) or the wake fails. While waiting, the platform re-checks the machine state with the cloud and re-issues the start command if it never landed; a connected tunnel counts as proof of readiness even when the server status has not refreshed yet. Use the blocking mode when the client needs readiness before the next step (a cron job, a triggered call), and the asynchronous one when you can afford to poll.

## Parameters

| Parameter | In | Type | Required | Default | Description |
|----------|---|-----|:-----:|-----------|----------|
| `id` | path | string (UUID) | yes | — | ID of a server in `sleeping` or `provisioning` status |
| `wait` | query | string | no | — | `true` — blocking mode: the response returns only when the server is ready (up to 6.5 minutes) or the wake fails. Any other value — asynchronous mode, the response returns immediately |

The request body is empty.

## Examples

### curl — personal key

```bash
# Asynchronous call — responds immediately, check readiness by polling
curl -X POST -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/wake

# Blocking — waits for readiness up to ~6.5 minutes
curl -X POST -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/wake?wait=true"
```

### 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/wake?wait=true"
```

### JavaScript — personal key

```javascript
// Blocking variant — simplest for subsequent steps
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/wake?wait=true`,
  { method: 'POST', headers: { 'X-Api-Key': 'YOUR_API_KEY' } }
)
const body = await res.json()
if (!body.success) {
  // Rich error: show userMessage to the user, offer alternatives
  console.error(body.error.userMessage ?? body.error.message)
  if (body.error.alternatives) console.log('Options:', body.error.alternatives)
  throw new Error(body.error.code)
}
console.log(`Server ready: ${body.data.appUrl}`)
```

### JavaScript — OAuth application

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

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` on a successful wake |
| `data.id` | string (UUID) | Server ID |
| `data.status` | string | Current status in lowercase (`running` on success with `wait=true`; `provisioning` in asynchronous mode) |
| `data.blackholeStatus` | string | Tunnel state (`CONNECTED` in blocking mode on success) |
| `data.appUrl` | string \| null | HTTPS address of the application |

## Response example

Successful wake (`?wait=true`):

```json
{
  "success": true,
  "data": {
    "id": "e765edfc-ba0a-43de-b8ea-838dd872c522",
    "status": "running",
    "blackholeStatus": "CONNECTED",
    "appUrl": "https://app-05b67cf7.vibecode.bitrix24.com"
  }
}
```

## Error response example

402 — the balance is frozen, and the server will not come up until the balance is topped up (rich error for AI agents):

```json
{
  "success": false,
  "error": {
    "code": "BILLING_EXHAUSTED",
    "message": "Balance depleted — top up to resume",
    "userMessage": "Your Vibecode balance is empty. Top up to resume your servers.",
    "alternatives": [
      { "type": "topup", "description": "Top up your balance in the billing section" }
    ],
    "hint": "Ask the user to top up their VibeCode balance. After top-up the server can be woken normally."
  }
}
```

## 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 |
| 402 | `INT_TARIFF_REQUIRED` | A Galaxy app: the account access check stops the wake of the galaxy host because the Bitrix24 account is on a free plan. A dedicated virtual machine does not get this code — its wake does not check the plan |
| 402 | `BILLING_EXHAUSTED` | The Vibecode balance is exhausted — top it up |
| 402 | `ACCOUNT_FROZEN` | The balance is frozen |
| 402 | `INT_VIBE_PLUS_REQUIRED` | A Galaxy app: access is narrowed to the Vibe+ plan line and the account is on an ordinary commercial plan, so the access check stops the wake of the galaxy host. Code breakdown — [Errors](/docs/errors) |
| 403 | `VIBE_DEMO_EXPIRED` | The server is a Vibe+ trial machine and the trial has ended: the platform froze it at the scheduled access check and refuses to wake it. This check runs before the wake-block and billing checks. The server and its data are kept; a paid Vibe+ plan on the Bitrix24 account restores access; the server is not started automatically — start it with a new call |
| 403 | `SERVER_WAKE_BLOCKED` | Wake blocked for a non-billing reason (expired platform access, an administrative block, security violations). For a Galaxy app the same code is returned when waking is blocked on the galaxy host |
| 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) |
| 403 | `EXTERNAL_COLLABORATOR_KEY_SERVER_MISMATCH` | The call was made with an external-collaborator key, and the address names a server other than the one the key was issued for. Such a key is valid for exactly one server, and the response does not reveal whether the requested server exists. Working with another server requires the key issued for that external membership |
| 403 | `EXTERNAL_COLLABORATOR_NOT_A_MEMBER` | An external-collaborator key addresses its own server, but access is not granted right now: the membership was removed, it expired, or external development collaborators are switched off for the Bitrix24 account that owns the server. The code does not tell these reasons apart and reveals nothing about the server. Membership is re-read on every request, so revoked access stops working immediately |
| 404 | `SERVER_NOT_FOUND` | The server does not exist, was deleted, or belongs to another API key while you are not on its development team |
| 404 | `NOT_FOUND` | The server was deleted while the call was in progress |
| 404 | `GALAXY_HOST_NOT_FOUND` | A Galaxy app: the galaxy host it runs on was not found |
| 409 | `WAKE_IN_PROGRESS` | Another request with `?wait=true` is already waking the server, or maintenance is running on the galaxy host. Wait for it to finish and read the [server state](/docs/infra/servers/get) before retrying |
| 409 | `RESIZE_IN_PROGRESS` | The server's configuration is being changed. The server starts on its own once that finishes, so no retry is needed. Track readiness by polling the [server state](/docs/infra/servers/get) |
| 409 | `CONFLICT` | The server state changed between the check and the start: another request has already woken it or moved it to a different status. Read the [server state](/docs/infra/servers/get) and decide whether another call is needed |
| 409 | `MANAGED_SERVER_LIFECYCLE` | The server belongs to an AI agent or a bot. Its start is controlled from the agent or bot card, not by `/wake` |
| 422 | `VM_MISSING` | The record has no `externalId` and the cloud review sees no machine under this server's cloud name — the virtual machine was not created on the provider side. Replace the server: delete it and create a new one. `error.hint` names the endpoint of each step only if that step is available to this request, and for an unavailable step it gives the reason for the refusal and what to change. The `error.userMessage` field arrives only when both steps are available |
| 422 | `VM_POINTER_LOST` | The record has no `externalId`, but the cloud review does see a machine under this server's cloud name: the link is lost while the machine itself is most likely running and billed. Do NOT delete the server and create a new one — that would leave the machine running with no record at all. The server is not moved to `error`; contact support to have the link restored |
| 422 | `SERVER_WRONG_STATE` | The server is not in `sleeping` or `provisioning` status, so `/wake` does not apply to it. The response carries `currentState` and `availableActions` — the server's current state and the actions available for it. A Galaxy app that has never had code uploaded and an app in `error` status get the same refusal: `/wake` does not recover a failed build. `error.message` names the code-upload call that fixes this |
| 422 | `CREDENTIAL_MISSING` | A Galaxy app: the galaxy host has no cloud-provider access attached — contact support |
| 422 | `GUEST_NOT_BOOTING` | A galaxy host or a Galaxy app on it: the host machine's guest operating system does not boot. The state is terminal, and retrying the wake will not help |
| 429 | `RATE_LIMITED` | The request rate limit was exceeded. The response carries a `Retry-After` header with the recommended pause |
| 502 | `PROVIDER_ERROR` | The cloud provider returned an error while starting the virtual machine |
| 502 | `WAKE_FAILED` | Server readiness could not be confirmed. This response does not mean that the server was stopped. Check the [current server state](/docs/infra/servers/get) before taking another action |
| 503 | `WAKE_NO_CAPACITY` | Startup has already been refused for lack of capacity. Read the [current server state](/docs/infra/servers/get) before trying again |
| 503 | `WAKE_TIMEOUT` | The blocking `?wait=true` call timed out (~6.5 minutes) before the server became ready: either the machine never came up or the tunnel never connected. The server returns to `sleeping` — a repeat call is safe |

The full list of common API errors — [Errors](/docs/errors).

## Known specifics

- **State changed while waiting.** If the state has already changed when cancellation is attempted, this call does not stop the server. A ready server in the `running` state with a connected tunnel and no wake block returns success. Unconfirmed readiness returns `502 WAKE_FAILED`; an existing refusal for lack of capacity retains `503 WAKE_NO_CAPACITY`. Read the [current server state](/docs/infra/servers/get) before taking another action.

- **Behavior on a `?wait=true` timeout.** If the virtual machine has not come up within ~6.5 minutes, the endpoint returns `503 WAKE_TIMEOUT` and tries to roll the server back to `sleeping` — so the quota is not left hanging on a "forever stuck" server. Inside that window the platform re-issues the start command whenever the cloud loses it, so a timeout means the machine genuinely did not come up, not that the command went missing. Retry `/wake` or call [`/repair`](./repair.md).
- **Rich-error fields for AI agents.** On 402/403 the error body additionally contains `userMessage` (a localized message for the user), `alternatives` (a list of resolution paths), and `hint` (advice to the AI agent on whether to retry automatically or not). Use these fields in the UI instead of the bare `code`/`message`.
- **A request to the subdomain does not always wake the server.** A wake is triggered in four cases: the server has [access policy](/docs/infra/access/access-policy) `PUBLIC`, the visitor is authenticated, the request carries an [access token](/docs/infra/access-tokens) in `api-bearer` mode, or the recipient opens a `share-url` link. A server with a wake block does not come up in these cases either — see the item below. An unauthenticated request to a server with any other policy, including the default `OWNER_ONLY`, leaves the server in `sleeping` status and gets an authentication refusal. Both representations use HTTP `401`: browser navigation gets the HTML sign-in page, while a machine-shaped request gets JSON `BH_LOGIN_REQUIRED`. JSON is selected by `Accept: application/json`, `Content-Type: application/json`, `Authorization: Bearer`, `X-Api-Key`, `X-Requested-With: XMLHttpRequest`, a `/v1/…` or `/api/…` path, or any non-navigation `Sec-Fetch-Dest` value (including `empty`); a request with neither explicit HTML nor a destination also defaults to JSON. These signals take precedence over explicit HTML and `Sec-Fetch-Dest: document|iframe|frame`. A bare `POST` with `Accept: */*` therefore gets JSON `401`. On a server with policy `PUBLIC`, `GET` and `HEAD` requests from search crawlers and automated clients — for example `curl`, `wget`, `python-requests`, `go-http-client`, `java/`, headless browsers, and a request with no `User-Agent` header — do not bring the machine up, so that crawling does not keep it running. On such a server `POST`, `PUT`, `PATCH`, and `DELETE` requests wake it from any client: those are webhook and API calls, not crawling. From a script or a console, bring the server up with an explicit `/wake` and `wait=true` — then the response arrives once the server is already accepting requests.
- **A server with the `preventWake` flag is not brought up by `/wake`** — the refusal codes are in the table above. The flag is set when the balance is frozen, platform access ends, or an administrative block is applied, and a server that belongs to an agent or a bot gets it on any stop — from its card or through [`/sleep-now`](./sleep-now.md). A standalone server is brought up by [`/start`](./start.md): it clears the block, but does not bypass a frozen balance. For a Galaxy app, a block on the host blocks `/start` as well — see [Galaxy app](/docs/infra/galaxy).
- **Check availability BEFORE the call.** Before calling `/wake`, call [`GET /v1/me`](/docs/keys-auth) and look at `capabilities.servers.wake.available`. If it is `false`, waking is unavailable right now: the balance is frozen or the key is restricted, and the `reason` field names the cause. The flag accounts for neither the plan nor the server's own wake block, so `403 SERVER_WAKE_BLOCKED` is possible even when it is `true`.
- **The machine's public address is different after a wake.** A woken machine receives a new address, so the `ip` field in [`GET /v1/infra/servers/:id`](/docs/infra/servers/get) returns a different value after every sleep cycle. This applies to all plans. Whatever reaches the server by its address — a DNS record, external monitoring — should point at the HTTPS subdomain in the `appUrl` field instead: a wake does not change it. The opposite direction has no such fix: when an external service admits only an allowlist of IPs, there is nothing to put on that list — the platform provides no permanent outbound address in any placement model, see [Outbound IP](/docs/infra/galaxy#outbound-ip).
- **`/wake` is not suitable for an `error` server** — use [`/start`](./start.md) or [`/repair`](./repair.md).

## Galaxy apps (`kind=GALAXY_APP`)

On a Galaxy app, `?wait=true` does not wait for readiness: the response arrives immediately, and the `WAKE_TIMEOUT` code never occurs here. After a cold host boot the app stays in `sleeping` status for a while — track readiness by polling [`GET /v1/infra/servers/:id`](/docs/infra/servers/get).

A Galaxy app wake first applies the current secret set to the container. The apply state is the `state` field of [`GET /v1/applications/:id/secrets`](/docs/applications/app-secrets/list).

The full map of an app's lifecycle operations is on the [Galaxy app](/docs/infra/galaxy) page.

## See also

- [Start the server](./start.md)
- [Sleep now](./sleep-now.md)
- [Repair tunnel](./repair.md)
- [Plan and access](/docs/infra#plan-and-access)
