Host Control WebSocket API Guide
The Host Control WebSocket API is the browser and outside-runtime integration boundary exposed by the control backend.
Use it for dashboards, package frontends, monitoring tools, and other clients that should not join native R2Kernel transport directly. Native subsystems should use the Subsystem SDK API.
This is the supported integration path for browser clients, packaged frontends, Windows/macOS tools, cloud services, and other non-R2Kernel clients. Those clients connect to a R2Kernel host through the control backend instead of opening native runtime transport.
This page explains the WebSocket flow. For the table-oriented endpoint and message catalog, see Host Control WebSocket Messages.
Endpoints
| Path | Direction | Purpose |
|---|---|---|
/api/v1/ws/events |
server stream with client subscription commands | Observe Event channels |
/api/v1/ws/control |
request/response messages | Invoke Procedure and Operation calls through the host control backend |
These are canonical API endpoints: API security, not Console login, determines
whether a key is required. Native or server-side external clients send
Authorization: Bearer <api-key> or X-R2Kernel-API-Key: <api-key> during the
handshake when API security is ON. Console cookies never authenticate these
paths, including on a shared listener.
Browser Console clients instead use /console/api/v1/ws/events and
/console/api/v1/ws/control on the actual Console origin, with a Console session
when login is ON. Console HTTP defaults to 18080; enabled native HTTPS defaults
to 18443 and uses wss. Canonical API defaults to 8001. Explicit overrides
are preserved; only explicit control.ui_port: 0 shares the API listener.
The browser WebSocket constructor cannot set arbitrary authentication headers.
Do not put API keys in URLs, query parameters, or subprotocols. A product browser
client needing the authenticated canonical API uses its own server-side adapter
to attach the key; it does not borrow a Console session. Package frontends can
use their declared instance-scoped proxy with their own product authentication.
With authentication required for the selected surface, Events requires
viewer access and Control requires operator or admin. Console login and
API security are independent; network admission applies to both.
For a same-origin Console page, the handshake URL can be constructed as follows
(sign in at /console/api/v1/auth/login first when Console login is ON):
const url = new URL("/console/api/v1/ws/events", window.location.origin);
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
const events = new WebSocket(url);
/api/v1/ws/events
/api/v1/ws/events is subscribe-only. It observes native Event channels and streams
matching messages to the browser-facing client.
Subscribe
{
"kind": "subscribe",
"topic": "example/status"
}
or.
{
"kind": "subscribe",
"topics": ["example/status", "example/state"]
}
Response example.
{
"kind": "subscribed",
"ok": true,
"topics": ["example/status"]
}
For all Event socket message kinds, see Host Control WebSocket Messages.
Unsubscribe
{
"kind": "unsubscribe",
"topic": "example/status"
}
Response example.
{
"kind": "unsubscribed",
"ok": true,
"topics": ["example/status"]
}
Clear
{
"kind": "clear"
}
Response example.
{
"kind": "cleared",
"ok": true
}
Event Message
{
"kind": "event",
"topic": "example/status",
"publisher": "controller",
"ts": 1234567890,
"payload_b64": "...",
"data": "...",
"payload_text": "{\"state\":\"running\"}",
"payload_json": {"state": "running"}
}
data is currently the same base64 payload as payload_b64 for browser
compatibility. Prefer payload_b64 for new clients.
There is no WebSocket Event publish path. Browser clients observe Event traffic; they do not inject native Event samples into the runtime through this endpoint.
/api/v1/ws/control
/api/v1/ws/control is a request/response facade over the native control path.
The browser does not call the timed exchange runtime directly. The control backend resolves the target subsystem and invokes Procedure or Operation through the native runtime boundary.
Ping
{
"kind": "ping",
"request_id": "client-1"
}
Response example.
{
"kind": "pong",
"ok": true,
"request_id": "client-1"
}
Procedure Call
{
"kind": "procedure.call",
"request_id": "req-1",
"target": "io_gateway",
"procedure": "set_output",
"params": {"index": 1, "value": true},
"timeout_ms": 1000
}
Response example.
{
"kind": "procedure.response",
"request_id": "req-1",
"target": "io_gateway",
"procedure": "set_output",
"ok": true,
"result": {"value": true},
"error_code": null,
"error_message": null
}
Operation Start
{
"kind": "operation.start",
"request_id": "op-1",
"target": "arm",
"operation": "move_j",
"params": {"positions": [0.0, 0.1, 0.2]},
"timeout_ms": 1000
}
Response example.
{
"kind": "operation.start.response",
"request_id": "op-1",
"target": "arm",
"operation": "move_j",
"ok": true,
"accepted": true,
"operation_id": "runtime-operation-id",
"state": "accepted",
"error_code": null,
"error_message": null
}
Operation Query
{
"kind": "operation.query",
"request_id": "op-query-1",
"target": "arm",
"operation_id": "runtime-operation-id",
"timeout_ms": 1000
}
Response example.
{
"kind": "operation.query.response",
"request_id": "op-query-1",
"target": "arm",
"ok": true,
"operation_id": "runtime-operation-id",
"operation": "move_j",
"state": "running",
"cancel_requested": false,
"feedback_count": 3,
"result": null,
"state_payload": {"progress": 0.3},
"created_ts": 1234567890,
"updated_ts": 1234567999,
"error_code": null,
"error_message": null
}
Operation Cancel
{
"kind": "operation.cancel",
"request_id": "op-cancel-1",
"target": "arm",
"operation_id": "runtime-operation-id",
"timeout_ms": 1000
}
The response shape matches operation.query.response with
kind="operation.cancel.response".
For all Control socket request and response kinds, see Host Control WebSocket Messages.
Error Response
Unsupported or invalid requests return an error response.
{
"kind": "error",
"request_id": "req-1",
"ok": false,
"error": "unsupported kind: example"
}
Boundary Rule
This WebSocket API is an outside-runtime facade.
/api/v1/ws/eventsobserves Event traffic/api/v1/ws/controlinvokes ordinary Procedure and Operation calls- timed execution is not exposed as a direct WebSocket control feature
- native hot-path communication remains under Event, Control, Procedure, and Operation in the SDK
- clients that need native timed exchange should be implemented as R2Kernel subsystems on a supported Linux runtime host
- clients that stay outside the native runtime should use this API rather than reimplementing native transport
For architecture context, see WebSocket Facade.