> ## Documentation index
> Fetch the complete documentation index at: https://developer.rhombus.com/llms.txt
> Use it to discover all available pages before exploring further.

# Robot Live Socket

> Drive a Rhombus robot and read its telemetry over a WebSocket: getting the socket URL, frame formats, the commands you send and the telemetry you receive, generated from the robot's AsyncAPI specification.

Each Rhombus robot has a live WebSocket for control and telemetry: you send commands such as velocity, posture and emergency stop, and receive the robot's pose, state, planned path, behavior events and sensor data. The message reference below is generated from the robot's [AsyncAPI specification](https://developer.rhombus.com/asyncapi/robot.json), so it always matches what the service publishes.

## Connect

1. Call [`getAllMediaUris`](https://developer.rhombus.com/api-reference/robot-webservice/get-media-uris-for-every-configured-facet-of-a-robot) for the robot and take `wanLiveRobotUri`, a `wss://` URL on the robot's media host.
2. Open a WebSocket to that URL with a credential (see [Authenticate](https://developer.rhombus.com/robots/live-socket#authenticate)).
3. Send commands as **text frames** holding JSON. Every command needs `type` and `timestamp` (Unix epoch milliseconds); the robot silently drops a command without them.
4. Read messages from the robot as **binary frames** holding UTF-8 JSON, and switch on their `type`.

### Authenticate

The socket accepts an API key, an OAuth access token or a federated token. Send it on the WebSocket handshake:

| Client               | Credential                                                                                              | How                                                                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Server or native app | API key                                                                                                 | Headers `x-auth-scheme: api-token` and `x-auth-apikey`                                                                             |
| Server or native app | OAuth access token whose grant includes the `physical` scope                                            | Header `Authorization: Bearer <token>`                                                                                             |
| Browser              | [Federated token](https://developer.rhombus.com/authentication/federated-tokens) minted by your backend | Query parameters `?x-auth-scheme=federated-token&x-auth-ft=<token>` (or the same names as headers, from clients that can set them) |

- Moving a robot is a physical action, so an OAuth token needs the `physical` scope: without it the handshake is refused with 403 `PERMISSION_REQUIRED` and `WWW-Authenticate: Bearer error="insufficient_scope", scope="physical"`.
- Partner credentials also send the client organization's UUID in the `x-auth-org` header.
- A refused handshake returns 401 (credential missing, unknown, expired or revoked) or 403 (valid but not allowed) with the JSON error body described in [Errors](https://developer.rhombus.com/errors).
- If the credential is deleted or revoked, or its role changes, the open socket closes with code `1008` within 60 seconds. Check the credential before reconnecting.

See [Media and streams](https://developer.rhombus.com/authentication/media) for how each credential works on the media hosts.

### Connection behavior

If the robot isn't connected to the media host in the URL, the handshake is refused with `403`: get `wanLiveRobotUri` again (the robot's media host can change) and retry later. If the robot is connected but its control channel isn't ready, the socket sends a [`reconnect`](https://developer.rhombus.com/robots/live-socket#reconnect) message as a text frame and stays open: close it and try again shortly. The socket closes after 180 seconds without traffic.

New message types, fields and enum values can be added at any time, so ignore what you don't recognize. A [`BEHAVIOR_EVENT`](https://developer.rhombus.com/robots/live-socket#behavior_event) can arrive twice when the robot retries a delivery; deduplicate by its `event_uuid`.

> **Warning**: Commands move a physical machine. Keep emergency stop ([`CMD_EMERGENCY_STOP_LOCK`](https://developer.rhombus.com/robots/live-socket#cmd_emergency_stop_lock)) one action away in any interface you build, stop sending velocity commands when your operator lets go of the control, and test in a clear area.

## Messages you send

### `CMD_ACTION`

Run a platform-specific action; see the action field for the values each robot platform supports.

```json
{
  "action": "GO2_STAND_UP",
  "timestamp": 1727800000000,
  "type": "CMD_ACTION"
}
```

### `CMD_EMERGENCY_STOP_LOCK`

Engage the emergency stop. The robot stays stopped until CMD_EMERGENCY_STOP_UNLOCK.

```json
{
  "timestamp": 1727800000000,
  "type": "CMD_EMERGENCY_STOP_LOCK"
}
```

### `CMD_EMERGENCY_STOP_UNLOCK`

Release the emergency stop.

```json
{
  "timestamp": 1727800000000,
  "type": "CMD_EMERGENCY_STOP_UNLOCK"
}
```

### `CMD_INITIALIZE_POSE`

Set the robot's localization estimate to a pose in the map frame.

```json
{
  "pose": {
    "orientation": [
      0,
      0,
      0,
      1
    ],
    "position": [
      0.5,
      0,
      0
    ]
  },
  "timestamp": 1727800000000,
  "type": "CMD_INITIALIZE_POSE"
}
```

### `CMD_NAVIGATE_CANCEL`

Cancel navigation: the current pose, waypoint, home, route/patrol, idle docking or exploration activity, plus queued ones. Low-battery docking continues.

```json
{
  "timestamp": 1727800000000,
  "type": "CMD_NAVIGATE_CANCEL"
}
```

### `CMD_POSTURE`

Adjust body posture. axes is a sparse map of platform-specific axis name to value (e.g. pitch in rad); empty or missing axes returns to neutral.

```json
{
  "axes": {
    "pitch": -0.1
  },
  "duration_ms": 5000,
  "timestamp": 1727800000000,
  "type": "CMD_POSTURE"
}
```

### `CMD_VEL`

Teleoperate with a velocity twist in the robot base frame: linear \[x, y, z] in m/s, angular \[x, y, z] in rad/s.

```json
{
  "timestamp": 1727800000000,
  "twist": {
    "angular": [
      0,
      0,
      0.2
    ],
    "linear": [
      0.3,
      0,
      0
    ]
  },
  "type": "CMD_VEL"
}
```

## Messages you receive

### `BEHAVIOR_EVENT`

Activity lifecycle and progress: STARTED, PROGRESS, SUSPENDED, RESUMED, COMPLETED, FAILED, CANCELED or REJECTED.

```json
{
  "activity": "ROUTE_RUN",
  "activity_uuid": "kX9mQ2rTSa6vL0pWcYb1Ng",
  "battery": {
    "start_pct": 91
  },
  "description": "Patrol run",
  "distance_remaining": 6.4,
  "estimated_time_remaining_sec": 18,
  "event": "PROGRESS",
  "event_uuid": "Q1w2E3r4T5y6U7i8O9p0AQ",
  "goal_pose": {
    "orientation": [
      0,
      0,
      0.7071,
      0.7071
    ],
    "position": [
      4.2,
      -1.5,
      0
    ]
  },
  "navigation_time_sec": 42.5,
  "originator_uuid": "Zx8Cv7Bn6Mm5Ll4Kk3Jj2A",
  "phase": "NAVIGATE_TO_WAYPOINT",
  "phase_uuid": "G7Qpbx5-RnC9av0WwS3jbA",
  "prediction": {
    "available": true,
    "confidence": "HIGH",
    "consumption_pct": 4.5,
    "distance_basis": "planned",
    "distance_m": 120
  },
  "priority": 50,
  "route_uuid": "Pz5Lc8Xe1Wa4Ru7Ty0Io3Q",
  "started_at_ms": 1727799950000,
  "timestamp": 1727800000000,
  "type": "BEHAVIOR_EVENT",
  "waypoint_index": 2,
  "waypoint_total": 5,
  "waypoint_uuid": "Hw4Rt7Yp2Kd9Vs3Bn6Mq1w"
}
```

### `LASER_SCAN`

Nearest obstacle per angular sector around the robot.

```json
{
  "frame": "base_footprint",
  "indices": [
    0,
    1,
    2,
    35
  ],
  "max_range_m": 3,
  "ranges": [
    1.25,
    null,
    2.4,
    0.8
  ],
  "sectors": 36,
  "timestamp": 1727800000000,
  "type": "LASER_SCAN"
}
```

### `OCCUPANCY_GRID`

Live occupancy grid of the map being built or used.

```json
{
  "data_compressed": "eJxjYASC1FRGBgZGRgAFWwDS",
  "height": 3,
  "origin": [
    -10,
    -5,
    0
  ],
  "resolution": 0.1,
  "timestamp": 1727800000000,
  "type": "OCCUPANCY_GRID",
  "width": 4
}
```

### `PLANNED_PATH`

Planned navigation path as \[x, y] points.

```json
{
  "frame": "map",
  "poses": [
    [
      1.2,
      -0.4
    ],
    [
      1.8,
      -0.2
    ],
    [
      2.5,
      0.1
    ]
  ],
  "timestamp": 1727800000000,
  "type": "PLANNED_PATH"
}
```

### `ROBOT_STATE`

Robot state: locomotion, battery, navigation mode and latest pose.

```json
{
  "avoidance_mode": "GO2_AVOIDANCE_MODE",
  "battery_current_ma": -3200,
  "battery_level": 82,
  "battery_state": "DISCHARGING",
  "battery_voltage_mv": 28600,
  "latest_transform": {
    "frame": "map",
    "transform": {
      "rotation": [
        0,
        0,
        0.38,
        0.92
      ],
      "translation": [
        1.2,
        -0.4,
        0
      ]
    }
  },
  "locomotion_state": "STANDING",
  "map_uuid": "bL0cfvn7Squz3-swZjifpg",
  "navigation_stack_state": "NAVIGATING",
  "operational_state": "OPERATIONAL",
  "return_home": {
    "available": true,
    "confidence": "HIGH",
    "distance_basis": "planned",
    "distance_m": 38.5,
    "required_pct": 7.2,
    "sufficient": true
  },
  "timestamp": 1727800000000,
  "type": "ROBOT_STATE"
}
```

### `TELEMETRY`

Robot pose sample. correlationId is the activity_uuid of the activity in progress.

```json
{
  "activity": "ROUTE_RUN",
  "correlationId": "kX9mQ2rTSa6vL0pWcYb1Ng",
  "frame": "map",
  "mapUuid": "bL0cfvn7Squz3-swZjifpg",
  "timestamp": 1727800000000,
  "transformation": {
    "rotation": [
      0,
      0,
      0.38,
      0.92
    ],
    "translation": [
      1.2,
      -0.4,
      0
    ]
  },
  "type": "TELEMETRY"
}
```

### `reconnect`

Sent by the cloud when the robot is not connected; reconnect later.

```json
{
  "action": "reconnect",
  "reason": "device_not_connected"
}
```
