> For the complete documentation index, see [llms.txt](https://docs.roboflow.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.roboflow.com/deployment/self-hosted/enterprise/deployment-manager.md).

# Deployment Manager

## About

Roboflow Deployment Manager lets you easily set up, deploy, and manage computer vision models on edge devices. After training your model and building a workflow, it provides an all-in-one solution for scaling deployments.

You can use Deployment Manager to:

1. Set up new devices with the [Roboflow Inference server](/deployment/self-hosted/self-hosted.md).
2. Configure camera streams for use in a deployment.
3. Deploy [Workflows](https://docs.roboflow.com/workflows) on the edge.
4. Monitor logs, stream status, and telemetry for deployed edge devices.

{% hint style="warning" %}
Deployment Manager is available exclusively for Enterprise customers. [Contact the Roboflow sales team](https://roboflow.com/sales) to learn more about this feature and how it can be used to manage your deployments at scale.
{% endhint %}

<figure><img src="/files/3kiR21SMqAeYJSHoFtbt" alt=""><figcaption></figcaption></figure>

### Key Requirements:

Deployment Manager is built for Roboflow-supported hardware:

* Supported: Hardware purchased via Roboflow
* Unsupported (use at your own risk): NVIDIA Jetson, x86 machines running Debian-based Linux with NVIDIA GPUs
* Not yet supported: Mac or Windows-based systems

Devices must be connected to the internet for setup and ongoing operation, with continuous access to Roboflow for remote management and monitoring.

### Edge Services

Alongside the inference server, a device can run additional Roboflow [Services](/deployment/self-hosted/enterprise/deployment-manager/services.md). Add and configure them from the device's Configuration tab, described in [Update Device Configuration](/deployment/self-hosted/enterprise/deployment-manager/making-changes/update-device-configuration.md).

* [Event Store](/deployment/self-hosted/enterprise/deployment-manager/services/event-store.md) stores inference events on the device, with automatic retention and optional cloud backup.
* [OPC UA Server](/deployment/self-hosted/enterprise/deployment-manager/services/opc-ua-server.md) publishes data as OPC UA tags for PLCs and SCADA systems.
* [PLC Relay](/deployment/self-hosted/enterprise/deployment-manager/services/plc-relay.md) reads and writes PLC tags over Allen-Bradley, Modbus TCP, or Siemens S7.
* [RTSP Simulator](/deployment/self-hosted/enterprise/deployment-manager/services/rtsp-simulator.md) streams an uploaded video file as an RTSP source for testing.

Each service serves its own HTTP API on the device's address. See [Services](/deployment/self-hosted/enterprise/deployment-manager/services.md#using-the-apis) for the base URL, authentication, and error-shape rules they share.

## Guides

### Setting Up

Follow the [Setting Up](/deployment/self-hosted/enterprise/deployment-manager/setting-up.md) guides in order to get a device online and running Workflows.

| Guide                                                                                                                      | Description                                                              |
| -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| [Hardware Requirements](/deployment/self-hosted/enterprise/deployment-manager/setting-up/hardware-requirements.md)         | Supported hardware, cameras, network, and outbound traffic requirements. |
| [Add a Device](/deployment/self-hosted/enterprise/deployment-manager/setting-up/add-a-device.md)                           | Provision a new edge device and register it with your account.           |
| [Add a Stream](/deployment/self-hosted/enterprise/deployment-manager/setting-up/add-a-stream.md)                           | Configure a camera stream that runs a Workflow.                          |
| [Set up Device Alerts](/deployment/self-hosted/enterprise/deployment-manager/setting-up/set-up-device-alerts.md)           | Enable email alerts for connectivity, disk, and FPS issues.              |
| [Setup Maintenance Windows](/deployment/self-hosted/enterprise/deployment-manager/setting-up/setup-maintenance-windows.md) | Schedule when deploy-affecting changes take effect.                      |

### Making Changes

The [Making Changes](/deployment/self-hosted/enterprise/deployment-manager/making-changes.md) guides cover updating, reconfiguring, and removing devices and streams after setup.

| Guide                                                                                                                                  | Description                                                        |
| -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| [Update Device Configuration](/deployment/self-hosted/enterprise/deployment-manager/making-changes/update-device-configuration.md)     | Manage device settings, service versions, and additional services. |
| [Configure Device Network](/deployment/self-hosted/enterprise/deployment-manager/making-changes/configure-device-network.md)           | Set IP addressing, gateway, DNS, and hostname from the cloud.      |
| [Configure AI1 Camera Settings](/deployment/self-hosted/enterprise/deployment-manager/making-changes/configure-ai1-camera-settings.md) | Tune exposure, gain, focus, and other AI1 camera settings live.    |
| [Set a Static IP for a Camera](/deployment/self-hosted/enterprise/deployment-manager/making-changes/set-camera-static-ip.md)           | Assign a persistent static IP to a GigE Basler or Lucid camera.    |
| [Soft Reset a PoE Port](/deployment/self-hosted/enterprise/deployment-manager/making-changes/soft-reset-poe-port.md)                   | Power-cycle a PoE port to recover stuck camera links.              |
| [Pause and Resume a Stream](/deployment/self-hosted/enterprise/deployment-manager/making-changes/stop-a-stream.md)                     | Temporarily pause a running stream and resume it later.            |
| [Trigger a Stream](/deployment/self-hosted/enterprise/deployment-manager/making-changes/trigger-a-stream.md)                           | Run a Workflow on demand against a Triggered stream.               |
| [Terminate a Stream](/deployment/self-hosted/enterprise/deployment-manager/making-changes/delete-a-stream.md)                          | Permanently remove a stream and its configuration.                 |
| [Redeploy Deployment Manager](/deployment/self-hosted/enterprise/deployment-manager/making-changes/redeploy-deployment-manager.md)     | Recover a device's configuration after a failure.                  |
| [Delete a Device](/deployment/self-hosted/enterprise/deployment-manager/making-changes/delete-a-device.md)                             | Permanently remove a device you no longer use.                     |
| [API Keys for Deployment Manager](/deployment/self-hosted/enterprise/deployment-manager/making-changes/api-keys-for-device-manager.md) | How device API keys are generated, scoped, and revoked.            |

### Monitoring

The [Monitoring](/deployment/self-hosted/enterprise/deployment-manager/monitoring.md) guides show how to check stream status, logs, resources, and Event Store health.

| Guide                                                                                                                      | Description                                                   |
| -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| [View a Stream](/deployment/self-hosted/enterprise/deployment-manager/monitoring/view-a-stream.md)                         | View a stream's status, latest frame, and Workflow details.   |
| [View Device Logs](/deployment/self-hosted/enterprise/deployment-manager/monitoring/view-device-logs.md)                   | Search, filter, and download logs from Roboflow services.     |
| [View the Resource Monitor](/deployment/self-hosted/enterprise/deployment-manager/monitoring/view-the-resource-monitor.md) | Monitor disk, memory, CPU, GPU, and service container health. |
| [View Event Store Status](/deployment/self-hosted/enterprise/deployment-manager/monitoring/view-event-store-status.md)     | Monitor Event Store usage, backup progress, and history.      |

## HTTP API

The Deployment Manager API lets you monitor and manage your Roboflow Deployment Manager (RFDM) devices programmatically.

All endpoints are mounted under `/:workspace/devices/v2` on the public API host (`https://api.roboflow.com`). Read endpoints require a [scoped API key](https://docs.roboflow.com/reference/authentication/authentication/scoped-api-keys) with the `device:read` scope; endpoints that change a device require `device:update`. Workspace API keys with no explicit scopes list are implicitly granted all scopes (legacy behavior); keys that carry an explicit `scopes` array must include the relevant scope.

With the Deployment Manager API, you can:

* [List and Get Devices](#list-and-get-devices)
* [Create a Device](#create-a-device)
* [Device Config](#device-config)
* [Device Commands](#device-commands)
* [Device Streams](#device-streams)
* [Device Logs and Telemetry](#device-logs-and-telemetry)
* [Device Events](#device-events)

The optional edge services (Event Store, PLC Relay, RTSP Simulator, OPC UA Server) serve their own HTTP APIs on the device's address rather than through `api.roboflow.com`. They do not accept a Roboflow API key, and their authentication and error shapes differ from everything below. See [Services](/deployment/self-hosted/enterprise/deployment-manager/services.md#using-the-apis).

### Authentication

All endpoints accept a workspace API key via either:

* Query string: `?api_key=YOUR_API_KEY`
* Header: `Authorization: Bearer YOUR_API_KEY`

#### Device-scoped API keys

API keys minted for a specific device (for example, by RFDM during install) are narrowed to that device. They may only call routes whose `:deviceId` path parameter equals the key's bound device. They will receive **403** on the workspace-wide list and create endpoints, and on any `:deviceId` path that doesn't match.

### Cross-workspace isolation

A workspace API key can only read or modify devices that belong to its workspace. Requests for a device id owned by a different workspace return **404**, even if the id is otherwise valid.

### Errors

| Status | Meaning                                                                                                                                                                                                                                                                |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | Invalid query parameter (unknown `time_period`, malformed cursor or date, invalid `direction`, etc.) or invalid request body.                                                                                                                                          |
| 401    | Missing or invalid API key.                                                                                                                                                                                                                                            |
| 403    | Device-scoped API key targeting a different device, the workspace-wide list/create routes, a source device from another workspace during duplication, or a feature-gated request rejected (for example, AI1 creation or `offline_mode` not enabled for the workspace). |
| 404    | Device, stream, config, or source device not found. Read requests for device ids owned by another workspace also return 404.                                                                                                                                           |
| 429    | Rate limit exceeded. Logs are limited to 5 requests per minute per IP and 50 per minute globally; telemetry reads are limited to 60 requests per minute per device with a 10-request burst over 10 seconds.                                                            |

Error responses use one of two shapes:

* Handler-level errors (typically 400, 403, 404, and 429 from the handlers themselves) return `{ "error": "<message>" }`.
* Authentication and workspace-validation failures (typically 401) return a structured `error` object: `{ "error": { "message": "...", "status": 401, "type": "OAuthException", "hint": "..." } }`.

The logs rate limiter additionally returns a plain string body (not JSON) when it triggers a **429**.

### List and Get Devices

#### List Devices

List every device registered in the workspace. Device-scoped API keys cannot call this endpoint and receive **403**.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2?api_key=$ROBOFLOW_API_KEY"
```

**Example Response**

```json
{
  "data": [
    {
      "id": "abc123",
      "name": "factory-floor-cam-1",
      "status": "online",
      "last_heartbeat": "2026-04-28T12:00:00.000Z",
      "platform": "Linux",
      "platform_release": "5.10.104-tegra",
      "platform_version": "#1 SMP PREEMPT ...",
      "architecture": "aarch64",
      "hostname": "jetson-01",
      "rfdm_version": "1.2.3",
      "type": "jetson",
      "hardware": {
        "processor": "aarch64",
        "gpu": null,
        "total_memory_mb": null,
        "total_disk_space_mb": 124426534912
      },
      "tags": ["production", "line-3"],
      "created_at": "2026-01-15T08:30:00.000Z"
    }
  ]
}
```

The `status` field is `online` if a heartbeat was received within the last 5 minutes, `offline` if older, or `unknown` if no heartbeat has ever been recorded. Newly-provisioned devices appear in the list before their first heartbeat; until then `status` is `unknown` and most monitoring-derived fields are `null`.

{% hint style="warning" %}
`hardware.total_disk_space_mb` is a raw value reported by the device. Despite the `_mb` suffix, RFDM-reported devices currently return this value in bytes (for example `124426534912` for a \~124 GB disk). Treat the unit as device-defined.
{% endhint %}

#### Get Device

Retrieve a single device by id. Returns **404** if the device does not exist or belongs to a different workspace.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}?api_key=$ROBOFLOW_API_KEY"
```

The response body matches a single item from the list endpoint (not wrapped in a `data` array).

### Create a Device

Create a new device in your workspace and return the identifiers needed to install it. Device-scoped API keys cannot call this endpoint and receive **403**.

**Required scope:** `device:update`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2" method="post" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl -X POST "https://api.roboflow.com/{workspace}/devices/v2?api_key=$ROBOFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"device_name": "factory-floor-cam-2", "device_type": "edge"}'
```

**Example Response**

```json
{
  "deviceId": "abc456",
  "installId": "inst_xyz789"
}
```

Use the returned `installId` to bootstrap the device with the Roboflow Deployment Manager installer.

#### Notes on AI1 devices

* Setting `device_type` to `"ai1"` requires the workspace to have the `deviceAio` feature enabled, otherwise the request returns **403**.
* `offline_mode` is only valid for AI1 devices on workspaces with `roboflowLiteMode`. Other combinations return **400** or **403**.
* For AI1 devices that are not duplicating an existing device and do not specify a `workflow_id`, the slugified `device_name` must contain at least one alphanumeric character, otherwise the request returns **400**.
* When AI1 + offline mode applies, the response also includes an `offlineProvisioningQrPayload` field encoding the QR payload for offline provisioning.

#### Notes on duplication

When `sourceDeviceId` is supplied, the new device is created from a copy of the source device's config. The source device must belong to the same workspace as the request, otherwise the request returns **403**. A non-existent `sourceDeviceId` returns **404**.

### Device Config

#### Get Workspace Default Config

Returns the workspace-level default device configuration. This is the base default config with the workspace's config patch (if any) merged in. Use it as a template when provisioning a new device before calling `POST /:workspace/devices/v2`.

**Required scope:** `device:read`

{% hint style="info" %}
This is a workspace-wide endpoint. Device-scoped API keys will receive **403** since there is no `:deviceId` in the path.
{% endhint %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/default-config?api_key=$ROBOFLOW_API_KEY"
```

**Example Response**

```json
{
  "config": {
    "version": "1.0.0",
    "config": {
      "inference": { "confidence": 0.7, "threshold": 0.3 },
      "device_type": "edge"
    },
    "services": {}
  },
  "patch": {
    "config": {
      "inference": { "confidence": 0.7 }
    }
  }
}
```

* `config` -- the merged result (base default + workspace patch).
* `patch` -- the workspace's stored patch. Empty object `{}` if the workspace has no custom patch.

#### Get Config

Returns the device's current runtime configuration. The response shape mirrors the Roboflow Deployment Manager (RFDM) config spec.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/config" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}/config?api_key=$ROBOFLOW_API_KEY"
```

The response is the full configuration document and includes (but is not limited to) the following top-level fields:

* `device_id`, `device_name`
* `workspace_id`
* `version`, `last_updated`, `last_updated_at`, `created_at`
* `config` (the device's runtime config tree, including `device_type`, `stream`, and `offline_mode`)
* `services` (per-service container definitions including `image`, `volumes`, and `environment_variables`)
* `environment_variables` (top-level environment variables, in addition to the per-service ones inside `services`)
* `production_mode`, `last_automatic_update`, `updated`, `updated_by`, `$schema`, `id`

Additional fields written by RFDM may also appear. Treat the response shape as open-ended and only depend on the fields you need.

Returns **404** if the device does not exist or does not belong to your workspace, or if no configuration is stored for it.

{% hint style="warning" %}
The response includes the full configuration as authored. Per-service `environment_variables` and any integration credentials embedded in the config are returned unredacted. Treat the response body as sensitive and do not log it in plaintext.
{% endhint %}

#### Config History

List prior configuration revisions for a device, newest first.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/config/history" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}/config/history?api_key=$ROBOFLOW_API_KEY&limit=10"
```

**Example Response**

```json
{
  "data": [
    {
      "revision_id": "rev_abc",
      "created_at": "2026-04-20T14:30:00.000Z",
      "created_by": "user_123"
    }
  ],
  "pagination": {
    "next_cursor": "...",
    "has_more": true,
    "limit": 10
  }
}
```

A malformed `cursor` returns **400** with `{"error": "Invalid cursor format"}`.

### Device Commands

Actions you start from the web app (ex: restart a device, pause a stream, scan for cameras) are queued as commands. The device picks them up on its next poll.

#### Get Pending Commands

Returns the commands waiting for a device, oldest first. Reading does not remove them: a command stays queued until the device reports back that it ran, so a device that restarts mid-command sees it again. Commands queued more than 5 minutes ago expire and are never delivered, because running them later would not match what you asked for.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/commands" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

#### Queue a Command

Queue a command for a device to run on its next poll. This does from the API what the web app does when you restart a device or start a stream.

**Required scope:** `device:update`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/commands" method="post" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

### Device Streams

#### List Streams

List every stream configured on a device.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/streams" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}/streams?api_key=$ROBOFLOW_API_KEY"
```

**Example Response**

```json
{
  "data": [
    {
      "id": "stream_abc",
      "name": "entrance-cam",
      "status": "running",
      "pipeline_id": "pipe_123",
      "workflow_id": "wf_456",
      "source": "rtsp://192.168.1.100:554/live",
      "started_at": "2026-04-28T10:00:00.000Z",
      "last_event_at": "2026-04-28T12:30:00.000Z",
      "camera_fps": 29.97,
      "inference_fps": 12.4,
      "sharpness": 0.82,
      "error": null
    }
  ]
}
```

**Source sanitization**

The `source` field is always passed through a sanitizer before it is returned:

* If the source is a URL, any `userinfo` (`scheme://user:pass@host/...`) is stripped. For example, `rtsp://admin:password@192.168.1.100:554/live` becomes `rtsp://192.168.1.100:554/live`.
* If the source is an object, keys whose lowercase name is `password`, `passwd`, `secret`, `api_key`, `apikey`, `auth`, `authorization`, `token`, or `access_token` are dropped from the response. All other keys are preserved.
* Arrays and nested objects are sanitized recursively.

#### Get Stream

Retrieve a single stream. Returns **404** if the stream does not exist on the device, or if the device does not exist or does not belong to your workspace.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/streams/{streamId}" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}/streams/{streamId}?api_key=$ROBOFLOW_API_KEY"
```

The response body matches a single item from the list endpoint (not wrapped in a `data` array).

#### Report Pipeline Status

Report the inference pipelines a device is running. Each reported pipeline updates the matching stream, along with its FPS and sharpness metrics. A stream declared in the device config is matched by its stream key, so it stops showing as provisioning once the device reports it.

RFDM posts this on devices that run without the device-manager container. Devices that run that container report the same data in their healthcheck, so they do not need this endpoint.

**Required scope:** `device:update`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/pipelines-status" method="post" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

You can also post the inference server's `/inference_pipelines/list` response unchanged, as `{"success": true, "data": {"pipelines": [...]}}`. If that body has `"success": false`, the device failed to list its pipelines, so the request is a no-op and leaves the existing streams alone.

### Device Logs and Telemetry

#### Logs

Returns paginated device logs.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/logs" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

**Rate limit:** 120 requests per minute per workspace. Log reads and log ingest use separate rate-limit buckets, so polling for logs will not count against your ingest quota (and vice versa).

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}/logs?api_key=$ROBOFLOW_API_KEY&limit=50"
```

**Example Response**

```json
{
  "data": [
    {
      "timestamp": "2026-04-28T12:01:00.000Z",
      "service": "inference",
      "severity": "INFO",
      "message": "Model loaded successfully"
    }
  ],
  "pagination": {
    "next_cursor": "2026-04-28T12:01:00.000Z",
    "has_more": true,
    "limit": 50
  }
}
```

**Rate limits**

This endpoint is rate-limited to **5 requests per minute per IP address** and **50 requests per minute globally**. Excess requests return **429**.

#### Telemetry

Returns aggregated hardware metrics (CPU, memory, disk, GPU) and per-stream FPS for a device, bucketed over a fixed time window.

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/telemetry" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}/telemetry?api_key=$ROBOFLOW_API_KEY&time_period=24h"
```

The bucket size is fixed per time period:

| `time_period` | `bucket_interval` | `fill_interval_seconds` |
| ------------- | ----------------- | ----------------------- |
| `1h`          | `2 MINUTE`        | 120                     |
| `24h`         | `30 MINUTE`       | 1800                    |
| `7d`          | `4 HOUR`          | 14400                   |
| `14d`         | `8 HOUR`          | 28800                   |

**Example Response**

```json
{
  "time_period": "24h",
  "bucket_interval": "30 MINUTE",
  "fill_interval_seconds": 1800,
  "buckets": [
    {
      "bucket_start": "2026-04-28T00:00:00.000Z",
      "cpu_pct": 42.5,
      "used_memory_mb": 3200,
      "total_memory_mb": 7860,
      "used_disk_space_mb": 15000,
      "total_disk_space_mb": 29000,
      "gpu_pct": 78.2
    }
  ]
}
```

Buckets in the requested window that received no telemetry are still returned, with each metric field set to `null`.

**Rate limits**

This endpoint is rate-limited per device to **60 requests per minute** with an additional **10 requests per 10 seconds** burst limiter. Excess requests return **429**. The same per-device telemetry quota is shared with the device's telemetry ingest path, so abusive reads can affect ingest for the same device.

### Device Events

Returns device and stream lifecycle events (for example device boots, stream starts and stops, errors, config changes).

**Required scope:** `device:read`

{% openapi src="/files/H5x9CDQa7dPNDXC9dDQe" path="/{workspace}/devices/v2/{deviceId}/events" method="get" %}
[deployment-manager.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-d164fd74955def36c4d130dbdd004404d00e4a61%2Fdeployment-manager.yaml?alt=media)
{% endopenapi %}

**Example Request**

```bash
curl "https://api.roboflow.com/{workspace}/devices/v2/{deviceId}/events?api_key=$ROBOFLOW_API_KEY&limit=50"
```

**Example Response**

```json
{
  "data": [
    {
      "id": "evt_abc123",
      "event": "device.boot",
      "entity_type": "device",
      "entity_id": "abc123",
      "event_description": "Device started up",
      "error_code": null,
      "metadata": { "source": "boot-loop" },
      "device_timestamp": "2026-04-28 10:00:00",
      "server_timestamp": "2026-04-28 10:00:01",
      "event_end_timestamp": null
    }
  ],
  "pagination": {
    "next_cursor": "...",
    "prev_cursor": "...",
    "has_more": true,
    "limit": 50
  }
}
```

The `device_timestamp`, `server_timestamp`, and `event_end_timestamp` fields are formatted as `YYYY-MM-DD HH:MM:SS[.SSS]` in UTC. They are not normalized to ISO-8601 like other timestamps in this API.

`event_end_timestamp` may also be returned as the epoch-zero string `"1970-01-01 00:00:00.000"` (rather than `null`) when the event has no recorded end timestamp.
