
## Servers for moving an application

`GET /v1/applications/:id/available-servers`

Shows where the owner can move the application: which of their own servers fit, and whether a new server can be created. Call it before you show the replace-server screen. The response tells you whether the replace button is needed and, if the replacement is unavailable, gives the reason as a code. The replacement itself is done by [`POST /v1/applications/:id/replace-server`](./replace-server.md).

Only the card owner can call this method. A Bitrix24 account administrator who does not own the application gets `403 FORBIDDEN`, just as with the replacement itself. This way a button that would end in a refusal is never shown.

**Authorization:** `X-Api-Key` with the `vibe:infra` scope.

## Parameters

| Parameter | Type | Required | Description |
|-----------|------|:--------:|-------------|
| `id` (path) | string | yes | Application ID. List: [`GET /v1/applications`](./list.md) |

## Examples

### curl — personal key

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/applications/cmsw806qi0000tdskiw2aegii/available-servers
```

### curl — OAuth application

```bash
curl -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.com/v1/applications/cmsw806qi0000tdskiw2aegii/available-servers
```

### JavaScript — personal key

```javascript
const id = 'cmsw806qi0000tdskiw2aegii'
const res = await fetch(`https://vibecode.bitrix24.com/v1/applications/${id}/available-servers`, {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const { data } = await res.json()

console.log('Own servers:', data.servers.map((s) => s.name))
if (!data.canCreateNew) {
  console.log('A new server is not available:', data.createNewBlocked.code)
}
```

### JavaScript — OAuth application

```javascript
const id = 'cmsw806qi0000tdskiw2aegii'
const res = await fetch(`https://vibecode.bitrix24.com/v1/applications/${id}/available-servers`, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})
const { data } = await res.json()
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` on success |
| `data` | object | Where the application can be moved |
| `data.servers` | array | The owner's servers the application can be moved to. At most 50, newest first. May be empty |
| `data.servers[].id` | string | Server ID. Pass it as `serverId` to [`POST /v1/applications/:id/replace-server`](./replace-server.md) |
| `data.servers[].name` | string | Server name |
| `data.servers[].displayName` | string \| null | Display name, if set |
| `data.servers[].status` | string | Server state in lowercase, as in [`GET /v1/infra/servers`](/docs/infra/servers/list) |
| `data.servers[].providerId` | string | Server provider |
| `data.servers[].plan` | string | Server plan |
| `data.servers[].region` | string | Server region |
| `data.servers[].kind` | string | `STANDALONE` — a separate machine, `GALAXY_APP` — an application container in a galaxy |
| `data.servers[].blackholeStatus` | string \| null | Tunnel state of the server |
| `data.servers[].createdAt` | string | Server creation time, ISO 8601 |
| `data.canCreateNew` | boolean | Whether the server can be replaced with a newly created one right now |
| `data.createNewBlocked` | object | Present only when `canCreateNew` is `false`, and names the reason |
| `data.createNewBlocked.code` | string | `ACCOUNT_FROZEN`, `INFRA_NOT_PERMITTED`, `SERVER_CREATION_DISABLED` or `SERVER_CREATION_ADMINS_ONLY` |
| `data.createNewBlocked.message` | string | Text for logs, in English |
| `data.createNewBlocked.userMessage` | string | Human-readable text in the key owner's language |
| `data.createNewBlocked.alternatives` | array | What can be done instead of creating a server. The shape matches the `402` response of [`POST /v1/applications/:id/replace-server`](./replace-server.md) |

## Response example

```json
{
  "success": true,
  "data": {
    "servers": [
      {
        "id": "srv_new",
        "name": "my-server",
        "displayName": null,
        "status": "running",
        "providerId": "bitrix-cloud",
        "plan": "bc-small",
        "region": "bc-eu-central",
        "kind": "STANDALONE",
        "blackholeStatus": null,
        "createdAt": "2026-10-01T09:00:00.000Z"
      }
    ],
    "canCreateNew": true
  }
}
```

## Error response example

403 — the application belongs to someone else, and a Bitrix24 account administrator replaces the server in their Vibecode account:

```json
{
  "success": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "Forbidden"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|------|-------------|
| 401 | `NO_PORTAL` | The key is not bound to a portal |
| 401 | `MISSING_API_KEY`, `INVALID_API_KEY` | No valid key |
| 402 | `ACCOUNT_FROZEN` | The portal balance is frozen and the whole `/v1` surface is closed. The body carries `message` and `topupUrl`. If only paid calls are closed, the method returns `200` with `canCreateNew: false` |
| 403 | `INFRA_SCOPE_REQUIRED` | The key lacks the `vibe:infra` scope |
| 403 | `INFRA_FORBIDDEN_FOR_COWORK_KEY` | A key with the `vibe:cowork` scope works with data only; this method is closed to it, reads included |
| 403 | `FORBIDDEN` | The application does not belong to the key owner |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key is read-only |
| 403 | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | Management key: use a personal key or an authorization key |
| 403 | `PORTAL_KEY_REQUIRED` | The key record is corrupted and has no owner. An ordinary key without a portal gets `401 NO_PORTAL` above |
| 404 | `APPLICATION_NOT_FOUND` | No such application on the portal the key is bound to. An application on another portal gets the same response |
| 429 | `RATE_LIMITED` | 60 requests per minute for the card owner, whichever key they use |

The `error.message` text is in English and meant for logs: build interface texts from `error.code`. The full list of common API errors is in [Errors](/docs/errors).

## Known specifics

- **Not all of the owner's servers are listed.** A server must belong to the card owner, exist, not be the application's current server, not be linked to another application, not be an agent or bot server and not be a galaxy host. The replacement does not accept a server that is not listed here: `POST /v1/applications/:id/replace-server` returns `404 SERVER_NOT_FOUND` or `409 SERVER_ALREADY_LINKED` for it.
- **An empty `servers` array does not block the replacement.** The server can also be replaced by creating a new one, if `canCreateNew` is `true`. Hide the replace button when the list is empty and `canCreateNew` is `false`, and take the reason from `createNewBlocked`.
- **A frozen balance closes creation only.** With `ACCOUNT_FROZEN` in `createNewBlocked`, moving to your own existing server stays available, and `servers` is filled by the same rules.
- **Creation depends on the account policy.** The codes `INFRA_NOT_PERMITTED`, `SERVER_CREATION_DISABLED` and `SERVER_CREATION_ADMINS_ONLY` mean the account policy does not let this person create servers. The replacement in the `new` form returns the same codes.
- **The response is a snapshot at the time of the call.** A server may be taken or deleted between this method and the replacement. The replacement rechecks everything itself and returns the matching code.
- **The method neither changes nor creates anything.** Call it as often as the screen needs.

## See also

- [Replace an application server](./replace-server.md)
- [Application card](./get.md)
- [Server list](/docs/infra/servers/list)
- [Application catalog](/docs/applications)
- [Errors](/docs/errors)
