A valid request URL is required to generate request examples{
"streamId": "<string>",
"transport": "edge-webrtc",
"expiresAt": "2023-11-07T05:31:56Z",
"tracks": [
{
"role": "screen",
"width": 123,
"height": 123,
"fps": 123,
"layers": [
"low"
]
}
],
"connect": {
"edge-webrtc": {
"url": "<string>",
"token": "<string>",
"room": "<string>"
},
"provider-rtc": {
"token": "<string>",
"baseUrl": "<string>",
"padCode": "<string>",
"userId": "<string>",
"resolution": 123
}
},
"clock": {
"serverTime": "2023-11-07T05:31:56Z",
"frameTiming": "sync_points"
},
"viewer": {
"role": "customer",
"defaultLayer": "low",
"priority": "customer"
},
"controls": {
"via": "api",
"actions": "<string>",
"events": "<string>"
},
"capabilities": {
"tracks": [
"screen"
],
"inputs": {
"tap": true,
"swipe": true,
"long_press": true,
"press_key": true,
"type_text": true,
"hover": true,
"hover_end": true
},
"keys": [
"home"
],
"multiTouch": true,
"rotate": true,
"hoverPremove": true,
"recording": true,
"unavailable": {}
},
"fallback": {
"transport": "snapshot",
"screenshot": "<string>",
"maxFps": 123
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "payload_too_large",
"message": "<string>"
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Open a live view of a device
Ask how to show this device’s screen live, and get everything the player needs in one answer. Every device answers with the same shape; transport says which entry of connect to use.
edge-webrtc: a robot-driven phone whose arm can publish video, on a deployment with a media server. connect["edge-webrtc"] holds the media server url, the room, and a token that can only receive, valid for joining until expiresAt: 10 minutes, or sooner when your organisation’s lease on the device ends sooner. Ask again before it lapses. The room belongs to the current lease: the next holder of the device gets a different room, so keep the lease if you want to keep the picture. The arm starts publishing when you first call this; calling again under the same lease keeps the running stream and returns the same streamId. An arm that is reachable but has nothing to publish (its screen feed is down, or it does not support video) answers snapshot instead. An arm that is reachable but not ready to act (for example awaiting calibration) can still be watched live when its screen feed is up; it has no still-image fallback, so otherwise it answers 409 like every other device route.
provider-rtc: a cloud phone. connect["provider-rtc"] holds the same five fields POST /v1/devices/{deviceId}/live-session returns, for the provider’s video SDK.
snapshot: no live video for this device here. Poll fallback.screenshot no faster than fallback.maxFps.
Controls never travel over the video channel. Send gestures to controls.actions as usual; controls.via is sdk only for a cloud phone with no agent run on it, whose player sends a person’s input through the provider. While a run drives a cloud phone, controls.via is api: send the person’s gestures to controls.actions, so the run is told somebody else acted before its next action. via is decided when you open the view; GET /v1/devices/{deviceId}/driving reports a run exactly while it would say api, so read that to notice a run starting or ending while the view is open. When this service cannot tell whether a run is on the device, it says api.
PERSON ONLY and YOU NEED THE SEAT, exactly as for a live session: a signed-in person with devices:act whose organisation holds a lease on the device (theirs, a colleague’s, or a running agent’s). Opening a view never takes the device or interrupts an agent. Tokens are credentials; do not store them.
Hosted deployments only. A local checkout does not mount this route, so calling it there is a 404.
A valid request URL is required to generate request examples{
"streamId": "<string>",
"transport": "edge-webrtc",
"expiresAt": "2023-11-07T05:31:56Z",
"tracks": [
{
"role": "screen",
"width": 123,
"height": 123,
"fps": 123,
"layers": [
"low"
]
}
],
"connect": {
"edge-webrtc": {
"url": "<string>",
"token": "<string>",
"room": "<string>"
},
"provider-rtc": {
"token": "<string>",
"baseUrl": "<string>",
"padCode": "<string>",
"userId": "<string>",
"resolution": 123
}
},
"clock": {
"serverTime": "2023-11-07T05:31:56Z",
"frameTiming": "sync_points"
},
"viewer": {
"role": "customer",
"defaultLayer": "low",
"priority": "customer"
},
"controls": {
"via": "api",
"actions": "<string>",
"events": "<string>"
},
"capabilities": {
"tracks": [
"screen"
],
"inputs": {
"tap": true,
"swipe": true,
"long_press": true,
"press_key": true,
"type_text": true,
"hover": true,
"hover_end": true
},
"keys": [
"home"
],
"multiTouch": true,
"rotate": true,
"hoverPremove": true,
"recording": true,
"unavailable": {}
},
"fallback": {
"transport": "snapshot",
"screenshot": "<string>",
"maxFps": 123
}
}{
"error": {
"code": "unauthorized",
"reason": "missing_credentials",
"hint": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}{
"error": {
"code": "payload_too_large",
"message": "<string>"
}
}{
"error": {
"code": "rate_limited",
"message": "<string>"
}
}{
"error": {
"code": "backend_resolution_failed",
"message": "<string>",
"retryable": true
}
}Authorizations
The control surface credential. Send Authorization: Bearer <token>.
Two kinds of token are accepted and they are told apart by shape, not by a separate header. A token beginning pbk_ is an org scoped API key, whose public half and secret half are generated together and of which only a hash of the secret is ever stored; anything else is treated as an OAuth 2.1 access token and verified against the authorization server's keys.
Both resolve to the same context: an org, a principal and a set of scopes. Nothing downstream branches on which channel you used, with one deliberate exception, key management, which requires a signed-in person so that a key can never mint another key.
Scopes are enforced when MCP tools are REGISTERED rather than when they are called, so a tool your credential cannot use is absent from tools/list rather than refused mid gesture.
Path Parameters
The deviceId from a listing.
Body
Optional. tracks and layer are accepted and not read yet: every view starts with the screen track on the high layer.
Response
How to show the device.
How to show one device live.
An opaque id for this view.
Which player to use, and which entry of connect it reads.
edge-webrtc, provider-rtc, snapshot When the viewing token stops admitting a new join, or null when there is none or it is not known. Ask again before it.
The video tracks on offer. Sizes and rates are nominal; the player reads the real ones from the stream.
Show child attributes
Show child attributes
Connection details keyed by transport; exactly the entry named by transport is present, and none for snapshot. edge-webrtc is {url, token, room} with a receive-only token; provider-rtc is {token, baseUrl, padCode, userId, resolution}. Tokens are credentials.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
What a player may offer on this device.
Show child attributes
Show child attributes
Show child attributes
Show child attributes