The screen, as a socket
Upgrades to a WebSocket carrying RFB — the VNC wire protocol — from the sandbox's display, for a host that brings its own client.
GET /v1/sandbox/{id}/screen/ws
| Address | https://api.hanzo.ai/v1/sandbox/{id}/screen/ws |
| Method | GET |
| Operation | get_sandbox_by_id_screen_ws |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Upgrades to a WebSocket carrying RFB — the VNC wire protocol — from the sandbox's display, for a host that brings its own client. Requires ticket; a missing, expired or already-spent one answers 401 without upgrading.
THE WIRE IS RFB, in BINARY frames both ways, and it is not interpreted here: this is a pipe between the caller's client and the server inside the pod.
THE PIXELS COME OUT THROUGH THE EXEC CHANNEL. The display binds 127.0.0.1 only and deliberately nothing else, so there is no address to dial — socat joins the stream to that loopback port over the same Kubernetes exec subresource every other call into a sandbox uses. One way in, one thing to authorize, nothing further exposed.
The window size is ignored. A browser pane is not the X server's geometry, and the client scales what it is given rather than asking a server with no RandR to resize itself.
Request
1 field.
| Field | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Response
The document declares no response body for this operation. It answers 200 on success and the platform error shape on failure — see Errors.
Examples
hanzo sandboxes screen ws <id>import { Configuration, SandboxApi } from 'hanzoai';
const api = new SandboxApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.getSandboxByIdScreenWs({ id: 'id' });from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import SandboxApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = SandboxApi(client).get_sandbox_by_id_screen_ws(id='id')cfg := cloud.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := cloud.NewAPIClient(cfg)
resp, _, err := client.SandboxAPI.GetSandboxByIdScreenWs(context.Background()).Execute()
if err != nil {
return err
}use hanzo_cloud::apis::{configuration::Configuration, sandbox_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = sandbox_api::get_sandbox_by_id_screen_ws(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.SandboxApi;
ApiClient client = new ApiClient();
client.setRequestInterceptor(b -> b.header("Authorization", "Bearer " + System.getenv("HANZO_API_KEY")));
var result = new SandboxApi(client).getSandboxByIdScreenWs();The method above is the one at the current release of the document. [email protected] (npm) and [email protected] (PyPI) were generated from an earlier release, where this operation carried a different id, so it spells the method differently — regenerating the clients is what makes the two agree. SDKs →
curl https://api.hanzo.ai/v1/sandbox/<id>/screen/ws \
-H "Authorization: Bearer $HANZO_API_KEY"The door reaches sandbox through the sandboxes tool, which names its 19 operations with its own verbs — this one among them, under a name only the door declares. describe explains any of them:
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe",
"arguments": {
"op": "list_sandboxes"
}
}
}'How is this guide?