Skip to main content
Request a short-lived viewer token to watch and control a session through a browser. The token grants access to one session and can be used in its viewer URL or stream connection. Treat it as a credential and keep the account API key on your server.

POST /v1/session/{session_id}/view-token

Response (200):
The token lasts 1800 seconds and is reusable until then. live_view_url is a path: prefix https://back.tilion.dev. The same token opens the WebSocket streams: wss://back.tilion.dev/v1/session/{id}/live?token=<token> and wss://back.tilion.dev/v1/session/{id}/webrtc?token=<token>. Errors: 404 or 410 for an unknown or ended session; 503 view tokens are not available on this deployment.

GET /v1/session/{session_id}/live-view

A ready-made interactive viewer page (text/html). Auth: ?token= from /view-token (no Bearer). Without a token: 401 missing view token; mint one with POST /v1/session/{id}/view-token. With a bad token: 403 invalid or expired view token. Those two answers come before any session lookup, so the status never reveals whether an id exists; an ended session with a valid token answers 410.

WS /v1/session/{session_id}/live

JPEG screencast of the page, interactive. URL: wss://back.tilion.dev/v1/session/{session_id}/live?token=<token> with the token from /view-token. The stream is a viewer: it does not hold the browser, so REST drive calls and fetch proceed normally while it is attached. What a client receives: text frames, each one base64 of a JPEG of the current page at the viewport size, delivered continuously at about 2 frames per second; consecutive frames can be byte-identical on a static page, so de-duplicate client side if you are storing them. Frames carry no timestamp; stamp them on receipt. The stream ends when the session ends. What a client sends, as JSON text frames:
  • {"t": "a"} after rendering a frame. Once you have sent one ack, frames are paced to your acks, so a slow viewer gets the newest frame instead of a growing backlog. A client that never acks gets every frame.
  • Mouse: {"t": "m", "type": "mousePressed" | "mouseReleased" | "mouseMoved" | "mouseWheel", "x": 120, "y": 80, "button": "left", "clickCount": 1, "dx": 0, "dy": 120} (page coordinates; button and clickCount for press and release; dx, dy for wheel).
  • Keyboard: {"t": "k", "type": "keyDown" | "keyUp" | "char", "key": "a", "code": "KeyA", "text": "a", "keyCode": 65}.
Input lands on the tab you are watching as real user input. Every view token allows input; there is no read-only token mode. A bad token is refused at the handshake with HTTP 403 and {"detail": {"error": "invalid_token", "message": "missing, expired or invalid token for this session; mint a new one"}}; an ended session is refused with its 410. The bytes streamed are billed as egress.

WS /v1/session/{session_id}/webrtc

A smooth video of the session over WebRTC, for viewers that can take it; the JPEG /live socket is the fallback. Auth: ?token=. The first message after the handshake:
Build an RTCPeerConnection with those iceServers (the TURN credential is short-lived and minted per connection), send {"type": "offer", "sdp": "..."} and receive {"type": "answer", "sdp": "..."}; the video track then flows peer to peer, and input rides this socket with the same {"t": "m" ...} and {"t": "k" ...} events as /live. When HD streaming is not available for this session right now the socket closes with code 1013 right after the handshake: keep the /live view you already have. Video bytes are billed as egress.

POST /v1/session/{session_id}/vnc-token

For a full_browser: true session: a token and URL to watch and drive the whole Chrome window (noVNC), not just the page. Response (200):
Open https://back.tilion.dev plus vnc_view_url in a browser or an iframe; it loads the viewer and connects it to the window. Errors: 404 full-browser (noVNC) view is not enabled on this deployment; 404 or 410 for the session; 503 when the token cannot be minted.

GET /v1/session/{session_id}/vnc/{path}

The noVNC viewer and its assets, served for one session. Auth: ?token= from /vnc-token on the first load, which also sets a cookie scoped to this path so the viewer’s own module imports work; without either, 403 invalid or missing view token. Directories are not listed. Assets are billed as egress.

WS /v1/session/{session_id}/vnc-ws

The VNC transport the viewer uses; binary frames (RFB). Auth: ?token= from /vnc-token. An attached VNC viewer holds the browser: REST drive calls answer 409 session_driven_by_client until it disconnects. Bytes are billed as egress.

Recordings

Set record: true on session creation to capture a frame replay. record: false disables capture; null uses the deployment default. A successful recording request returns replay_url, a tokenized path to an HTML player. Prefix it with https://back.tilion.dev. The player displays captured frames; the replay URL itself is not a video file. Capture stops at the plan’s recorded-minute cap while the browser session can continue:

GET /v1/recordings

Auth: Bearer API key. Returns {"recordings": [...]}, most recent first, up to 100 rows. Add ?session_id=<id> to filter. Each row carries session_id, rec_id, status, frame_count, duration_s, bytes, tier, cap_minutes, created_at and expires_at. Counts may not be final while capture is running.

GET /v1/recordings/{session_id}/{rec_id}/view

Auth: Bearer API key. Mint recording-scoped URLs: Prefix each returned path with https://back.tilion.dev and use it as returned, including its token. Mint fresh URLs when they expire. Unknown or inaccessible recordings answer 404.

GET /v1/recordings/{session_id}/{rec_id}/download

Use the tokenized download_url from /view. The default format is ZIP (application/zip), including captured frames, manifest.json and replay.html. A running recording can be downloaded with the frames captured so far. Close the session to finalize its recording. format=mp4 requests H.264 export. While recording is running it answers 409 recording_in_progress. After close, an available encoder can return 202 {"status": "processing"} while encoding; retry the same URL until it returns video/mp4. If the encoder is unavailable, the route answers 503 encoder not available; use the ZIP or replay player. Invalid or expired authorization answers 403; a missing recording answers 404.

DELETE /v1/recordings/{session_id}/{rec_id}

Auth: Bearer API key. Delete the recording; success is 204 No Content.