Skip to main content
An operator is one physical agent capable of producing a live video feed from a known place: a phone, a drone, a fixed camera, a ground robot. Operators belong to a supplier workspace — a workspace with SUPPLIER in its roles.

Operator vs. supplier workspace

These are two different objects:
ObjectWhat it is
Operator workspaceA workspace with SUPPLIER role. Has a Base wallet, API keys, members. Owns the API contract.
OperatorAn individual device/asset within the workspace. A fleet of drones is one workspace and many operators.
For the smallest case (one phone, one human), workspace and operator are 1:1. For fleets, one workspace operates many.
In early access, operator-as-asset registration is partially built — the FK exists in the schema, the management endpoints don’t yet. A session today is accepted at the workspace level; per-operator assignment is the next refinement.

Becoming a supplier

Create a workspace with SUPPLIER in roles — public endpoint, the signature in the body is the auth:
curl -X POST .../workspaces \
  -d '{
    "slug": "acme-drones",
    "name": "Acme Drone Co",
    "walletAddress": "0x...",
    "signature": "0x...",
    "nonce": "...",
    "roles": ["SUPPLIER"]
  }'
Sign in via SIWE (see Authentication) to obtain an lx_session cookie, then mint an API key with sessions:operate:
curl -X POST .../workspaces/$ID/api-keys \
  -b cookies.txt \
  -d '{
    "label": "drone-fleet-prod",
    "environment": "LIVE",
    "scopes": ["sessions:operate", "sessions:read", "wallet:read"]
  }'
That key is what your fleet software uses on every accept / start / end call.

Stream protocol

Operators publish over WHIP (WebRTC HTTP Ingest Protocol). Any compliant encoder works — Larix Broadcaster, OBS WebRTC, GStreamer with the WebRTC plugin, a drone’s onboard payload software, the browser’s getUserMedia (see Publish from a browser below).
POST <whipUrl>
Content-Type: application/sdp
The whipUrl is returned by POST /sessions/:id/start and is re-fetchable mid-session via GET /sessions/:id/producer-token (operator only). URLs are stable for the lifetime of the underlying Cloudflare Stream live_input; a publisher reconnecting after a crash just re-POSTs the SDP offer to the same URL — no new session lifecycle call needed.

Publish from a browser

For demos, smoke tests, or operators on phones, the console hosts an in-page browser publisher:
https://console.luxxon.dev/sessions/<sessionId>
In Operate mode the page authenticates via the operator’s wallet (SIWE), pulls the WHIP URL via /producer-token, opens getUserMedia (rear-cam preferred on mobile) + microphone, and negotiates a WebRTC publish. Start/stop is two clicks; the camera picker shows up when multiple cameras are present. The same lx-session cookie that gates the dashboard gates this page — no separate auth.

Reclaim a stuck workspace

If an operator device crashes (phone dies mid-stream, network flips, browser tab closes) the session can be left in ASSIGNED with the operator workspace pinned to BUSY and the Cloudflare live_input still minted. The pre-LIVE expiry cron sweeps these up eventually (at createdAt + maxDurationSeconds), but for a long session that’s too slow. The operator can reclaim everything immediately:
curl -X POST .../sessions/cancel-all-assignments \
  -H "Authorization: Bearer $OPERATOR_KEY"
Cancels every ASSIGNED session this workspace owns, releases the workspace to ONLINE, tears down each live_input. LIVE sessions are NOT affected — those still go through /end so the meter can run. Available in the console as the “Cancel N active assignments” button on the Operate side of /sessions. Scope: sessions:operate.

Telemetry contract

Operators publish position telemetry alongside the video. Spec’d in Trust model / Tier 1:
POST /sessions/:id/telemetry
{
  "capturedAt": "2026-05-13T08:42:00.123Z",
  "point": { "lat": 4.711, "lng": -74.072 },
  "accuracyMeters": 4,
  "source": "gps",
  "signature": "0x..."
}
≥ 1 Hz. The meter consults this log second-by-second at end — seconds without a fresh in-geofence sample become failedSeconds (non-billable, no earning, no fee).

Earnings

Every chargeable second of a session credits the operator workspace’s wallet:
operator_earned = cleanSeconds × ratePerSecond × (10000 − feeBps) / 10000
Settlement is atomic: the same on-chain transaction that takes the fee delivers the operator’s share. No batched payouts, no reconciliation window. See Settlement.

What we accept today vs roadmap

TodayRoadmap
Workspace-level accept/start/endPer-operator dispatch + selection
Wall-clock meterTelemetry-anchored meter
Public WHIP/WHEP contract documentedEdge tokens minted at start
One wallet per workspace(unchanged — by design)
C2PA-signed frames pass through unchangedFirst-class provenance flag in session response