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

> ## Agent Instructions
> These docs cover learner integrations through Hosted Lab Pages, the SDK, and the REST API. Content management is outside this integration scope.
> Read the setup page for the chosen approach before implementing it. Keep organization API keys and hosted mint secrets on the server.
> The public SDK is coming soon. Check the SDK quickstart for current availability. Do not invent installation commands or direct readers to a private package.
> Cybr provides completion tracking and CTF verification. The integrating platform decides whether to award points.

# Terminal WebSocket protocol

> Connect a direct WebSocket client with temporary terminal credentials.

The terminal uses a persistent WebSocket connection. It does not accept separate HTTP requests for individual shell commands.

The [browser SDK helper](/reference/terminal) handles this protocol. Direct clients can use the wire format on this page.

## Create credentials

Request a [terminal session](/api-reference/create-terminal-session) from the server. The response contains `wsUrl`, `expiresAt`, and an optional `protocols` array.

The URL and protocols can contain temporary credentials. They belong only to the deployment owner.

## Open the socket

Pass the protocols to the WebSocket constructor:

```ts theme={null}
const socket = new WebSocket(session.wsUrl, session.protocols ?? [])
socket.binaryType = 'arraybuffer'
```

The organization API key does not belong in this connection. A socket-open event does not mean that the shell is ready.

## Control messages

Control messages use text frames with JSON:

| Direction | Message | Meaning |
| - | - | - |
| Server to browser | `{"type":"ready"}` | The shell accepts input |
| Browser to server | `{"type":"resize","cols":80,"rows":24}` | Change the terminal dimensions |
| Server to browser | `{"type":"exit","code":0}` | The shell exited, with an optional code |
| Server to browser | `{"type":"error"}` | The terminal reported an error |

Before input, wait for `ready`. After readiness, send the latest terminal dimensions.

The SDK clamps dimensions to integers from 1 through 500. A direct client must also send valid positive dimensions.

## Input and output

Terminal data uses binary frames. Input is UTF-8 text:

```ts theme={null}
socket.send(new TextEncoder().encode('pwd\r'))
```

Binary output arrives as `ArrayBuffer` data. A terminal renderer can consume those bytes as a `Uint8Array`.

A text decoder must preserve partial UTF-8 characters between output frames. xterm accepts byte arrays directly.

## Reconnect and expiration

Every reconnect requires a new terminal-session request. The previous URL and protocols are not reusable credentials for a new connection.

The client does not replay previous input. A closed socket does not end the lab.

An expired or ended lab can reject session creation. The learner must request a separate lab launch to start another environment.

`expiresAt` is the deadline for connection authorization. It does not set the shell lifetime or deployment deadline.

An existing connection can continue after token expiration until the lab ends.
