Fleet
Bulk fleet operations
Apply one supported action to a reviewed robot selection and follow each target to a persisted terminal outcome. Command batches distinguish queued, accepted, unknown, and device-confirmed results.
On this page
Start here
Bulk operations apply one change to a reviewed fleet selection and preserve a result per target. Creation captures the target set, a worker processes robots independently, and operators watch asynchronous progress.
Before you begin
- Workspace operator access to the batch-operation endpoints
- Verified robot IDs or one filter, plus valid parameters and a partial-failure plan
Put it into practice
-
Preview the target set
Apply cohort, tag, status, model, or other supported fleet filters and verify the same selection in the fleet view. Keep it below the 5,000-target ceiling.
-
Create one batch
Choose explicit IDs or a filter, select the operation kind, and submit its parameters. Record the returned batch ID for status, targets, and audit correlation.
-
Monitor and resolve exceptions
Follow progress events or poll the batch. Inspect each failed target, retry only supported failures after correcting the cause, and cancel queued work when the original intent is no longer safe.
The batch reaches a terminal status, completed and failed target counts reconcile with the captured selection, and audit history shows who created, retried, completed, or cancelled the operation.
01 Operation kinds
reference| kind | params | Notes |
|---|---|---|
| set_status | {"status": "online"} | One of online, offline, charging, error, maintenance. pending and decommissioned are not settable. |
| apply_tags | {"tags": ["night-shift"]} | 1 to 32 tags, normalized before writing |
| remove_tags | {"tags": ["night-shift"]} | 1 to 32 tags |
| add_to_cohort | {"cohort_id": "uuid"} | Cohort must belong to the workspace |
| remove_from_cohort | {"cohort_id": "uuid"} | Cohort must belong to the workspace |
| dispatch_command | {"command_type": "reboot", "payload": {}} | command_type is 2-120 characters; payload must encode to at most 16,000 bytes |
| acknowledge_alerts | none | Acknowledges each target's active fleet alerts |
02 Selecting targets
detailsExplicit ids or a filter, never both
Supply robot_ids (a list) or filter (a map). If both are present robot_ids wins. Ids outside the workspace and decommissioned robots are dropped from an explicit selection; if that leaves nothing the request fails with empty_selection.
Filter keys
query, status, robot_type, cohort_id, and tag -- the same keys the fleet board puts in its URL. An empty filter selects every in-service robot.
5,000 target ceiling
Both selection modes are capped at 5,000 targets; a wider selection is rejected with selection_too_large rather than partially executed. The filter is snapshotted into filter_snapshot at creation, so the target list is fixed at submit time and does not drift as robots change.
03 Create a batch by filter
examplePOST /api/v1/operator/batch_operations
{
"batch_operation": {
"kind": "apply_tags",
"params": {"tags": ["night-shift"]},
"filter": {"cohort_id": "9c1e...", "status": "online"},
"reason": "Rolling out the night shift schedule"
}
}
Response 201:
{
"id": "...", "kind": "apply_tags", "status": "queued",
"selection_mode": "filter",
"filter_snapshot": {"cohort_id": "9c1e...", "status": "online"},
"total_count": 128, "succeeded_count": 0, "failed_count": 0, "skipped_count": 0,
"progress": {"queued": 128, "running": 0, "succeeded": 0, "failed": 0, "skipped": 0},
"targets": [{"id": "...", "target_type": "robot", "target_id": "...", "status": "queued",
"attempts": 0}]
}
04 Endpoints
reference| Method and path | Purpose | Success |
|---|---|---|
| GET /api/v1/operator/batch_operations | List batches. Filters: status, kind, limit. Rows omit progress and targets. | 200 |
| POST /api/v1/operator/batch_operations | Create a batch | 201 |
| GET /api/v1/operator/batch_operations/:id | Batch with progress and targets. Filters: target_status, target_limit. | 200 |
| POST /api/v1/operator/batch_operations/:id/cancel | Cancel a queued or running batch | 200 |
| POST /api/v1/operator/batch_operations/:id/retry_failed | Create a child batch over this batch's failed targets | 201 |
05 Status model
detailsBatch status
queued, running, completed, completed_with_errors, cancelled. For dispatch_command, cancellation first records cancel_requested_at and a separate cancel_reason. Known-unsent work can be cancelled locally; a linked command that may have reached a device remains running until its exact terminal result. cancelled does not prove physical stop.
Target status
queued, running, succeeded, failed, skipped. A command target retains the exact command_id, delivery_state and terminal outcome; accepted delivery alone is still running. Each target carries attempts, finished_at, a bounded error and a skip_reason such as target_missing, robot_decommissioned or batch_cancelled.
06 Progress, retry, and audit
detailsLive progress
Targets are processed in chunks of 25 on the dedicated fleet queue. One target's failure never aborts the batch. Counters are recomputed from persisted rows, not optimistic sends. fleet.batch_operation.* PubSub is best-effort after commit, not a durable outbox; poll the batch and its paginated targets after reconnect or missed progress.
Retrying
retry_failed creates a child batch referencing the parent through parent_id and covering only the failed targets, itself bounded by the 5,000 ceiling. A single target can also be retried from its detail view. Each failure is retried once from its batch, so repeating a retry never dispatches to the same robots twice; a failure that fails again is retried from the child batch that carried it.
Audit
Individual robot/mission/OTA/cohort/geofence/work-order/alert mutations and batch create/retry/cancel boundaries write scoped audit records with actor, reason and outcome. The command batch's target-command link is durable before dispatch, and a failed outcome remains discoverable by correlation rather than being silently treated as success.
07 Rejections
reference| Status | detail | When |
|---|---|---|
| 400 | invalid_kind | Unknown operation kind |
| 400 | invalid_status / invalid_tags | Bad params for the kind |
| 400 | invalid_command_type / invalid_payload | dispatch_command params out of bounds |
| 400 | empty_selection | Neither robot_ids nor filter, or nothing selectable |
| 400 | selection_too_large | More than 5,000 targets |
| 400 | not_cancellable | The batch already finished |
| 400 | no_failed_targets | Nothing to retry |
| 400 | already_retried | Every failure already has a retry batch |
| 422 | invalid cohort | cohort_id is not a cohort in this workspace |
| 422 | Validation failed (extra.errors.batch_operation or extra.errors.params: ["must be an object"]) | The batch_operation wrapper or its params value is not a JSON object |
| 404 | Resource not found | Unknown batch id |
Troubleshooting
- Creation is rejected
- An explicit robot_ids selection takes precedence when both IDs and filter are supplied; choose deliberately rather than sending both. Check for an empty selection, unsupported filter keys, invalid kind parameters, or more than 5,000 targets.
- The batch completes with failures
- A target failure does not roll back successful robots. Inspect target-level errors and retry only after the underlying state or parameters are corrected.
- Live progress was missed
- Realtime updates are convenient, not the sole record. Fetch the batch and its paginated targets to reconstruct authoritative progress.