> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runaether.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Ports Channel

> Open-port snapshots, change notifications, process kill, and preview URLs

The `ports` channel reports which network ports are listening inside the workspace and lets you kill the process behind one. Port detection comes from a monitor sidecar in the VM, so you never poll. See the [WebSocket overview](/api-reference/websocket/overview) for connecting.

## Server to Client

### `snapshot`

Sent on connect (and after a port refresh) with every currently-open port. Carries only port numbers.

```json theme={"dark"}
{ "channel": "ports", "type": "snapshot", "ports": [3000, 5173] }
```

### `change`

A single port opened or closed. There is one message type with an `action` discriminator — no separate `open`/`close` types, and no PID or process name.

```json theme={"dark"}
{ "channel": "ports", "type": "change", "action": "open", "port": 3000 }
```

| Field | Type | Description |
| - | - | - |
| `action` | `"open"` \| `"close"` | Whether the port started or stopped listening |
| `port` | integer | Port number (1–65535) |

## Killing a Process

### `kill` (client to server)

Terminate the process on a port. The request requires a `requestId` so you can match the response.

```json theme={"dark"}
{ "channel": "ports", "type": "kill", "requestId": "req-1", "port": 3000 }
```

### `killResponse` (server to client)

The response type is `killResponse` and echoes the `requestId`.

```json Success theme={"dark"}
{ "channel": "ports", "type": "killResponse", "requestId": "req-1", "success": true, "port": 3000 }
```

```json Failure theme={"dark"}
{
  "channel": "ports",
  "type": "killResponse",
  "requestId": "req-1",
  "success": false,
  "port": 3000,
  "error": "no process found on port 3000"
}
```

## Preview URLs

Each open port is reachable through a public preview URL built from the workspace's project ID prefix and its `preview_token` (returned by the [connect handshake](/api-reference/websocket/overview#connecting)):

```
https://{port}-{projectIdPrefix}-{previewToken}.{previewDomain}
```

* `port` — the listening port
* `projectIdPrefix` — the first 8 hex characters of the project ID
* `previewToken` — the 32-character lowercase alphanumeric `preview_token`
* `previewDomain` — the configured preview domain

The token segment is required — preview URLs without a valid token are rejected.

```
https://3000-abc12345-ab12cd34ef56ab12cd34ef56ab12cd34.preview.runaether.dev
```

The gateway resolves the workspace by project-ID prefix, validates the token against that workspace, and proxies both HTTP and WebSocket (HMR) traffic into the VM.

## Example Flow

```mermaid theme={"dark"}
sequenceDiagram
    participant Client
    participant Server as Aether

    Note right of Server: On connect
    Server->>Client: snapshot (ports: [])
    Note left of Client: Starts dev server on 3000
    Server->>Client: change (action: "open", port: 3000)
    Note left of Client: Preview URL live
    Client->>Server: kill (requestId: "req-1", port: 3000)
    Server->>Client: killResponse (requestId: "req-1", success: true, port: 3000)
    Server->>Client: change (action: "close", port: 3000)
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.