
## SSH credentials

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

Returns the SSH connection credentials. Full SSH credentials (password, private key, and public key) are returned only for servers in `OPEN` mode. A person switches `OPEN` mode on in the cabinet: [`PATCH /v1/infra/servers/:id/mode`](/docs/infra/access/mode) to `OPEN` answers `403 DIRECT_NETWORK_CHANGE_REQUIRES_HUMAN` for any API key. For `BLACKHOLE`, `sshPassword`, `sshPrivateKey`, `sshPublicKey`, and `sshCommand` are `null`, while `sshUser` and `sshPort` are omitted: the server is closed off by an iptables firewall, and direct SSH is not possible. For BLACKHOLE, use the [Deploy API](/docs/infra/deploy) instead of SSH — `/exec`, `/upload`, `/logs`. Rate limit: up to 10 requests per minute per server. The effective value is provided in the `x-ratelimit-limit` header.

`HEAD` is not supported at this address and returns `404`. Use `GET` to retrieve SSH credentials.

## Parameters

| Parameter | In | Type | Required | Description |
|----------|---|-----|:-----:|----------|
| `id` | path | string (UUID) | yes | Server ID |

## Examples

### curl — personal key

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

### curl — OAuth application

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

### JavaScript — personal key

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

if (data.mode === 'OPEN') {
  console.log('Command:', data.sshCommand)
  console.log('Password:', data.sshPassword)  // if it was issued
} else {
  console.log(data.note)  // BLACKHOLE — use the Deploy API
}
```

### JavaScript — OAuth application

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

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` on success |
| `data.mode` | string | `OPEN` or `BLACKHOLE` |
| `data.ip` | string | Public IP of the server |
| `data.sshDirect` | boolean | `true` for `OPEN` (SSH connects directly to the IP), `false` for `BLACKHOLE` (closed off by the firewall) |
| `data.sshUser` | string | SSH user: `ubuntu` or `root`. Omitted for `BLACKHOLE` |
| `data.sshPort` | number | SSH port: `22`. Omitted for `BLACKHOLE` |
| `data.sshPassword` | string \| null | Password. Always `null` for BLACKHOLE. For OPEN, the password the server generated when switching to OPEN, if any |
| `data.sshPrivateKey` | string \| null | The platform's private key in OpenSSH format (ed25519). Always `null` for BLACKHOLE |
| `data.sshPublicKey` | string \| null | Public key (ed25519) — the public part matching `sshPrivateKey` |
| `data.sshCommand` | string \| null | Ready-to-copy command: `ssh ubuntu@IP`. `null` for BLACKHOLE |
| `data.appUrl` | string | The application's HTTPS address (present only for BLACKHOLE, where SSH is unavailable) |
| `data.note` | string | Explanation for BLACKHOLE: "BLACKHOLE servers do not expose SSH. Use the Deploy API…" |

## Response example

OPEN server:

```json
{
  "success": true,
  "data": {
    "mode": "OPEN",
    "ip": "111.88.251.211",
    "sshUser": "ubuntu",
    "sshPort": 22,
    "sshPassword": "Oi9owBO6zMbueGmM75J9hg",
    "sshPrivateKey": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmU…\n-----END OPENSSH PRIVATE KEY-----\n",
    "sshPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM0JAP1EMGh0CkT7RkZ26pTSa4X1FsWXe61cB5Fiqqjz vibe-generated",
    "sshCommand": "ssh ubuntu@111.88.251.211",
    "sshDirect": true
  }
}
```

BLACKHOLE server:

```json
{
  "success": true,
  "data": {
    "mode": "BLACKHOLE",
    "ip": "93.77.184.167",
    "sshDirect": false,
    "sshPassword": null,
    "sshPrivateKey": null,
    "sshPublicKey": null,
    "sshCommand": null,
    "appUrl": "https://app-abc12345.vibecode.bitrix24.com",
    "note": "BLACKHOLE servers do not expose SSH. Use the Deploy API (exec/upload/logs) instead."
  }
}
```

## Error response example

404 — the server does not exist:

```json
{
  "success": false,
  "error": {
    "code": "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 | `SERVER_ROLE_FORBIDDEN` | You are on this server's development team with the Developer role, but this operation requires the Administrator role. `error.hint` includes your role, the minimum required role, and the API calls available to you. Role breakdown — [List servers](/docs/infra/servers/list) |
| 404 | `NOT_FOUND` | The server does not exist or belongs to another API key while you are not on its development team |
| 409 | `SERVER_NOT_READY` | The server has no assigned IP address yet |
| 429 | `RATE_LIMITED` | The limit of 10 requests per minute per server or the platform's overall rate limit was exceeded. The effective value is provided in the `x-ratelimit-limit` header |

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

## Known specifics

- **Each BLACKHOLE → OPEN switch generates a new password.** Old passwords (if any) become invalid. The same applies to a back-and-forth cycle BLACKHOLE → OPEN → BLACKHOLE → OPEN: each time the server enters OPEN, the platform generates a fresh `sshPassword`.
- **`sshPrivateKey` and `sshPublicKey` are the platform's key pair, not yours.** The platform creates this key pair for every server, so in `OPEN` mode both fields are returned even if you passed your own `sshPublicKey` when creating the server via [`POST /v1/infra/servers`](/docs/infra/servers/create). This request does not return your key: the platform does not store it. The platform installs your own key while the machine is being prepared, so you can connect with it once the server is switched to `OPEN` mode.
- **`sshCommand` is a ready-to-copy string for AI agents and scripts.** It is not a separate launch command — just `ssh ubuntu@IP`. Authentication via password or key is a separate step on the SSH client side.
- **A separate limit of 10 requests per minute per server** exists precisely because the returned data is sensitive. The effective value is provided in the `x-ratelimit-limit` header. The platform's overall limit is higher, but `/ssh` is throttled more strictly.

## See also

- [Switch mode](./mode.md)
- [Run a command](/docs/infra/deploy/exec)
- [Upload a file](/docs/infra/deploy/upload)
- [Access policy](./access-policy.md)
