
## Tunnel metrics

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

Returns the server's real-time activity data from the Black Hole Gateway: the agent's connection time, the most recent HTTP and SSH requests, and the number of active connections. Use it to monitor whether the application is alive, debug timeouts, and check auto-sleep. Works only for BLACKHOLE servers; if the Gateway is temporarily unavailable, the response still arrives with status 200, but with the field `available: false`.

## Parameters

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

## Examples

### curl — personal key

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

### 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/metrics
```

### JavaScript — personal key

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

if (data.available) {
  console.log(`Connected: ${data.connectedAt}`)
  console.log(`Last HTTP: ${data.lastRequestAt ?? 'never'}`)
  console.log(`HTTP connections: ${data.httpConnections}`)
} else {
  console.log('Gateway unavailable, the tunnel may still be working')
}
```

### JavaScript — OAuth application

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

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` — even when the Gateway is unavailable, the endpoint returns 200 with `available: false` |
| `data.available` | boolean | `true` — data was received from the Gateway. `false` — the Gateway does not respond (but the tunnel may still be working) |
| `data.subdomain` | string | The application's subdomain (always present) |
| `data.appUrl` | string | The application's HTTPS address (only when `available: true`) |
| `data.connectedAt` | string (ISO 8601) \| null | The moment the agent connected to the Gateway. `null` — the agent has never connected |
| `data.lastRequestAt` | string (ISO 8601) \| null | The moment of the last HTTP request to the application. `null` — no requests have been made |
| `data.lastSshActivityAt` | string (ISO 8601) \| null | The moment of the last SSH activity. Always `null` for modern BLACKHOLE servers (the SSH relay is disabled) |
| `data.httpConnections` | number | The number of active HTTP connections through the tunnel |
| `data.sshConnections` | number | The number of active SSH connections. Always `0` for modern servers |

## Response example

Gateway available:

```json
{
  "success": true,
  "data": {
    "available": true,
    "subdomain": "app-5ec02c7e",
    "appUrl": "https://app-5ec02c7e.vibecode.bitrix24.com",
    "lastRequestAt": null,
    "lastSshActivityAt": null,
    "connectedAt": "2026-04-22T11:16:32Z",
    "httpConnections": 0,
    "sshConnections": 0
  }
}
```

Gateway unavailable (normal behavior during a temporary outage):

```json
{
  "success": true,
  "data": {
    "available": false,
    "subdomain": "app-5ec02c7e"
  }
}
```

## Error response example

404 — not a BLACKHOLE server:

```json
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "BLACKHOLE 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, and this operation is open to the Administrator role. `error.hint` carries your role, the required threshold and the list of calls that are open to you. Role breakdown — [List servers](/docs/infra/servers/list) |
| 404 | `NOT_FOUND` | The server is not in BLACKHOLE mode, was deleted, or belongs to another API key while you are not on its development team. For an OPEN server the endpoint returns 404 (tunnel metrics are not applicable) |
| 429 | `RATE_LIMITED` | The platform's overall request limit was exceeded |

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

## Known specifics

- **HTTP 200 + `available: false` is not an error — it is normal behavior during a temporary Gateway outage.** The Gateway is temporarily not responding (a restart, network issues inside the platform), but the application **may** still be working — the tunnel will recover on its own. In the UI, show "metrics unavailable", not "server is down".
- **`connectedAt` resets on a Gateway restart.** If the Gateway was restarted (a rare event), `connectedAt` will show the moment of the agent's new connection. This does not mean the agent reconnected — the Gateway simply "forgot" the history.
- **`lastRequestAt: null` on a running server is normal.** It means no one has accessed the application's HTTPS subdomain. This is the field that resets the idle timer, so auto-sleep will soon put such a server to sleep: on a new machine auto-sleep is enabled with a 60-minute timeout. To turn it off, set the timeout to `null` — [Configure auto-sleep](/docs/infra/lifecycle/sleep).
- **`available: true` ≠ "the application is working".** It only means the Gateway returned data. The agent is connected, the tunnel is ready — but the application may not be listening on port 3000 and may return 503. To check health, make an HTTP request to `appUrl`.

## See also

- [Configure auto-sleep](/docs/infra/lifecycle/sleep)
- [Get a server](/docs/infra/servers/get)
- [Repair the tunnel](/docs/infra/lifecycle/repair)
- [Service logs](./logs.md)
