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

# Watch device

> `WS /v1/devices/{id}/watch` — upgrade, validate, then relay. The credential is offered as the
`omega.token.<ops_…>` subprotocol, NEVER as a query parameter (see [`token_from_subprotocols`]).

Validation happens BEFORE the upgrade so a rejected client gets a real HTTP status rather than a
WebSocket that immediately closes. Note the deliberate asymmetry with the rest of `/v1`: this
route authenticates with the SESSION token, not an API key. The session row is the tenancy claim —
its org and device are read from the row, never from the request.



## OpenAPI

````yaml /schemas/operator.json get /v1/devices/{id}/watch
openapi: 3.1.0
info:
  title: Omegas Operator API
  version: 0.1.0
  description: >-
    The public /v1 machine surface: cloud browser devices, tasks, live-view
    sessions, escalations, usage, webhook endpoints, and the audit trail.
    Generated from the same OpenAPI document the Rust API is checked against.
servers:
  - url: https://api.omegas.dev
    description: Production
security: []
paths:
  /v1/devices/{id}/watch:
    get:
      tags:
        - Endpoints
      summary: Watch device
      description: >-
        `WS /v1/devices/{id}/watch` — upgrade, validate, then relay. The
        credential is offered as the

        `omega.token.<ops_…>` subprotocol, NEVER as a query parameter (see
        [`token_from_subprotocols`]).


        Validation happens BEFORE the upgrade so a rejected client gets a real
        HTTP status rather than a

        WebSocket that immediately closes. Note the deliberate asymmetry with
        the rest of `/v1`: this

        route authenticates with the SESSION token, not an API key. The session
        row is the tenancy claim —

        its org and device are read from the row, never from the request.
      operationId: watch_device
      parameters:
        - name: id
          in: path
          description: Device id (`dev_<uuid>`)
          required: true
          schema:
            type: string
        - name: Sec-WebSocket-Protocol
          in: header
          description: >-
            Two subprotocols: `omega.operator.v1, omega.token.<ops_…>`. The
            credential travels here, NOT in the query string, so it is never
            recorded by request logging or error reporting.
          required: true
          schema:
            type: string
      responses:
        '101':
          description: >-
            WebSocket upgrade (echoes `omega.operator.v1`). Server→client:
            `{"t":"frame","data":<base64 jpeg>,"w":…,"h":…}`. Client→server:
            `{"t":"mouse"|"scroll"|"key"|"char", …}` — relayed ONLY for a
            `control` session that currently HOLDS the device's takeover lease.
        '410':
          description: >-
            session_expired — unknown, expired, revoked, or wrong-device token
            (one indistinguishable answer)

````