Deployment Manager
Manage and monitor computer vision models deployed on edge hardware.
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:
Set up new devices with the Roboflow Inference server.
Configure camera streams for use in a deployment.
Deploy Workflows on the edge.
Monitor logs, stream status, and telemetry for deployed edge devices.

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. Add and configure them from the device's Configuration tab, described in Update Device Configuration.
Event Store stores inference events on the device, with automatic retention and optional cloud backup.
OPC UA Server publishes data as OPC UA tags for PLCs and SCADA systems.
PLC Relay reads and writes PLC tags over Allen-Bradley, Modbus TCP, or Siemens S7.
RTSP Simulator 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 for the base URL, authentication, and error-shape rules they share.
Guides
Setting Up
Follow the Setting Up guides in order to get a device online and running Workflows.
Supported hardware, cameras, network, and outbound traffic requirements.
Provision a new edge device and register it with your account.
Configure a camera stream that runs a Workflow.
Enable email alerts for connectivity, disk, and FPS issues.
Schedule when deploy-affecting changes take effect.
Making Changes
The Making Changes guides cover updating, reconfiguring, and removing devices and streams after setup.
Manage device settings, service versions, and additional services.
Set IP addressing, gateway, DNS, and hostname from the cloud.
Tune exposure, gain, focus, and other AI1 camera settings live.
Assign a persistent static IP to a GigE Basler or Lucid camera.
Power-cycle a PoE port to recover stuck camera links.
Temporarily pause a running stream and resume it later.
Run a Workflow on demand against a Triggered stream.
Permanently remove a stream and its configuration.
Recover a device's configuration after a failure.
Permanently remove a device you no longer use.
How device API keys are generated, scoped, and revoked.
Monitoring
The Monitoring guides show how to check stream status, logs, resources, and Event Store health.
View a stream's status, latest frame, and Workflow details.
Search, filter, and download logs from Roboflow services.
Monitor disk, memory, CPU, GPU, and service container health.
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 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:
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.
Authentication
All endpoints accept a workspace API key via either:
Query string:
?api_key=YOUR_API_KEYHeader:
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
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
errorobject:{ "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
List every device registered in the workspace. Device-scoped API keys cannot call this endpoint and receive 403.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Devices in the workspace.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
GET /{workspace}/devices/v2 HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"data": [
{
"id": "text",
"name": "text",
"status": "online",
"last_heartbeat": "2026-01-01T00:00:00.000Z",
"platform": "text",
"platform_release": "text",
"platform_version": "text",
"architecture": "text",
"hostname": "text",
"rfdm_version": "text",
"type": "text",
"hardware": {
"processor": "text",
"gpu": "text",
"total_memory_mb": 1,
"total_disk_space_mb": 1
},
"tags": [
"text"
],
"created_at": "2026-01-01T00:00:00.000Z"
}
]
}Example Request
Example Response
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.
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
Retrieve a single device by ID.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
The device.
online if a heartbeat was received within the last 5 minutes, offline if older, unknown if no heartbeat has ever been recorded.
Version of the Roboflow Device Manager running on the device.
Device type reported by the device (for example "jetson").
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
GET /{workspace}/devices/v2/{deviceId} HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"id": "text",
"name": "text",
"status": "online",
"last_heartbeat": "2026-01-01T00:00:00.000Z",
"platform": "text",
"platform_release": "text",
"platform_version": "text",
"architecture": "text",
"hostname": "text",
"rfdm_version": "text",
"type": "text",
"hardware": {
"processor": "text",
"gpu": "text",
"total_memory_mb": 1,
"total_disk_space_mb": 1
},
"tags": [
"text"
],
"created_at": "2026-01-01T00:00:00.000Z"
}Example Request
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
Create a new device in the workspace and return the identifiers needed to install it. Device-scoped API keys cannot call this endpoint and receive 403. Requires the device:update scope.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Human-readable name for the device. For AI1 devices that are not duplicating an existing device and do not specify a workflow_id, the slugified name must contain at least one alphanumeric character, otherwise the request returns 400.
Device type. Common values are "ai1" and "edge"; any custom string is also accepted. AI1 creation requires the workspace to have the deviceAio feature enabled.
Optional initial workflow assignment. For AI1 devices it seeds the default aione stream.
Tags to attach to the device. Must be an array of non-empty strings; duplicates are removed and entries are trimmed.
Only valid for AI1 devices, and only if the workspace has the roboflowLiteMode feature.
Duplicate an existing device's config instead of generating a fresh one. The source device must belong to the same workspace.
Device created.
ID of the newly-created device.
Short-lived install token. Feed it into GET /devices/v2/{installId}/install.sh from the device to bootstrap RFDM.
Returned only for AI1 devices created in offline mode. Encodes the QR payload used by the offline RFDM provisioner.
Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
POST /{workspace}/devices/v2 HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 124
{
"device_name": "text",
"device_type": "text",
"workflow_id": "text",
"tags": [
"text"
],
"offline_mode": true,
"sourceDeviceId": "text"
}{
"deviceId": "text",
"installId": "text",
"offlineProvisioningQrPayload": "text"
}Example Request
Example Response
Use the returned installId to bootstrap the device with the Roboflow Deployment Manager installer.
Notes on AI1 devices
Setting
device_typeto"ai1"requires the workspace to have thedeviceAiofeature enabled, otherwise the request returns 403.offline_modeis only valid for AI1 devices on workspaces withroboflowLiteMode. Other combinations return 400 or 403.For AI1 devices that are not duplicating an existing device and do not specify a
workflow_id, the slugifieddevice_namemust contain at least one alphanumeric character, otherwise the request returns 400.When AI1 + offline mode applies, the response also includes an
offlineProvisioningQrPayloadfield 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
Example Request
Example Response
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
Returns the device's current runtime configuration. The response includes per-service environment_variables and any integration credentials embedded in the config; treat the body as sensitive.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
The current device configuration.
Full RFDM configuration document.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
GET /{workspace}/devices/v2/{deviceId}/config HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"ANY_ADDITIONAL_PROPERTY": "anything"
}Example Request
The response is the full configuration document and includes (but is not limited to) the following top-level fields:
device_id,device_nameworkspace_idversion,last_updated,last_updated_at,created_atconfig(the device's runtime config tree, includingdevice_type,stream, andoffline_mode)services(per-service container definitions includingimage,volumes, andenvironment_variables)environment_variables(top-level environment variables, in addition to the per-service ones insideservices)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.
Config History
List prior configuration revisions for a device, newest first.
Required scope: device:read
List prior configuration revisions for a device, newest first.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Number of revisions to return. Clamped to 1-500.
10Opaque pagination cursor from a previous response. Pass back next_cursor to fetch the next page.
A page of revisions, newest first.
Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
GET /{workspace}/devices/v2/{deviceId}/config/history HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"data": [
{
"revision_id": "text",
"created_at": "2026-01-01T00:00:00.000Z",
"created_by": "text"
}
],
"pagination": {
"next_cursor": "text",
"has_more": true,
"limit": 1
}
}Example Request
Example Response
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
Returns the commands queued for a device, oldest first. The read does not remove commands: each one stays queued until the device acknowledges it. Commands queued more than 5 minutes ago expire and are not returned.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
The commands waiting for the device.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
GET /{workspace}/devices/v2/{deviceId}/commands HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"commands": [
{
"id": "cmd_abc",
"action": "restart",
"data": {}
}
]
}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
Queue a command for a device. The device runs it on its next poll. This is the API equivalent of the actions you start from the web app.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
What the device should do. An action outside this list returns 400.
restartPossible values: The command was queued.
Command ID, used to match the device's acknowledgement.
cmd_abcInvalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
POST /{workspace}/devices/v2/{deviceId}/commands HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 30
{
"action": "restart",
"data": {}
}{
"id": "cmd_abc"
}Device Streams
List Streams
List every stream configured on a device.
Required scope: device:read
List every stream configured on a device, including streams that are set up in the device config but have not reported in yet, which are returned with a provisioning status. Credentials are stripped from URLs and known credential-bearing object keys are removed from each stream's source.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Streams configured on the device.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
GET /{workspace}/devices/v2/{deviceId}/streams HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"data": [
{
"id": "text",
"name": "text",
"status": "text",
"provisioning": true,
"mode": "continuous",
"pipeline_id": "text",
"workflow_id": "text",
"source": "text",
"configured_source": "text",
"started_at": "2026-01-01T00:00:00.000Z",
"last_event_at": "2026-01-01T00:00:00.000Z",
"camera_fps": 1,
"inference_fps": 1,
"sharpness": 82,
"error": "text",
"error_code": "STREAM_SOURCE_UNAVAILABLE",
"error_message": "text",
"error_retryable": true,
"status_events": [
{
"id": "text",
"event": "text",
"entity_type": "text",
"entity_id": "text",
"event_description": "text",
"error_code": "text",
"metadata": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"device_timestamp": "text",
"server_timestamp": "text",
"event_end_timestamp": "text"
}
]
}
]
}Example Request
Example Response
Stream errors
When a stream fails, error_code, error_message, and error_retryable describe the failure. They come from the most recent stream status event, so they clear when the stream recovers. Use error_code to branch in your own code, and error_retryable to see if the device retries the stream by itself. The older error field stays for compatibility.
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/livebecomesrtsp://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, oraccess_tokenare 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
Retrieve a single stream on a device. A stream that exists only in the device config is returned as a provisioning entry. Returns 404 when the stream exists neither live nor in the config.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Stream ID.
Set to status_events to attach the stream's 20 most recent lifecycle events from the last 7 days.
The stream.
Stream status reported by the streams service (for example "running", "stopped", or transitional states). Streams that exist in the device config but have not reported in yet are returned with status "provisioning".
True when the stream is in the config but has not reported in yet.
"triggered" for streams that run their Workflow only when triggered, "continuous" for streams that run all the time. Null when the stream has no config entry.
Sanitized source descriptor. URL userinfo is stripped; object keys named password, passwd, secret, api_key, apikey, auth, authorization, token, or access_token are removed.
Source taken from the device config, sanitized the same way as source. Filled in for provisioning streams that have no live source yet, and null otherwise.
Camera frame rate reported by the device heartbeat.
Inference pipeline frame rate reported by the device heartbeat.
Focus score of the most recent frame, reported by the device heartbeat. An integer from 0 (blurry) to 100 (sharp).
82Legacy free-text error from the device. Credentials are masked. An error reported as an object is returned as a JSON string.
Code for the most recent stream failure, taken from the latest status event. Codes are uppercase identifiers reported by the device. A failure with an unusable code becomes "STREAM_ERROR". Null when the stream is healthy or the status event has expired.
STREAM_SOURCE_UNAVAILABLEText that goes with error_code. Credentials are masked.
True when the device retries the stream by itself. Null when the device does not report it.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
GET /{workspace}/devices/v2/{deviceId}/streams/{streamId} HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"id": "text",
"name": "text",
"status": "text",
"provisioning": true,
"mode": "continuous",
"pipeline_id": "text",
"workflow_id": "text",
"source": "text",
"configured_source": "text",
"started_at": "2026-01-01T00:00:00.000Z",
"last_event_at": "2026-01-01T00:00:00.000Z",
"camera_fps": 1,
"inference_fps": 1,
"sharpness": 82,
"error": "text",
"error_code": "STREAM_SOURCE_UNAVAILABLE",
"error_message": "text",
"error_retryable": true,
"status_events": [
{
"id": "text",
"event": "text",
"entity_type": "text",
"entity_id": "text",
"event_description": "text",
"error_code": "text",
"metadata": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"device_timestamp": "text",
"server_timestamp": "text",
"event_end_timestamp": "text"
}
]
}Example Request
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
Report the inference pipelines a device is running. Each reported pipeline updates the matching stream, including its FPS and sharpness metrics. A stream that was declared in the device config is matched by its stream key and stops showing as provisioning. Devices running the device-manager container report the same data inside their healthcheck instead.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
When the status was measured, as a Unix timestamp in seconds or an ISO 8601 string. Defaults to the time the request is received.
2026-04-28T10:00:00ZThe reported pipelines were applied.
trueHow many reported pipelines had a pipeline_id.
1Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
POST /{workspace}/devices/v2/{deviceId}/pipelines-status HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 370
{
"pipelines": [
{
"pipeline_id": "entrance-cam",
"status": "RUNNING",
"camera_fps": 30,
"inference_fps": 14.5,
"sharpness": 82,
"stream_error_code": "STREAM_SOURCE_UNAVAILABLE",
"stream_error_message": "Camera did not answer the RTSP handshake.",
"stream_error_retryable": true,
"params": {
"video_reference": "rtsp://192.168.1.100:554/live",
"max_fps": 5
}
}
],
"timestamp": "2026-04-28T10:00:00Z"
}{
"success": true,
"updated": 1
}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
Returns paginated device logs. Rate-limited to 5 requests per minute per IP and 50 per minute globally.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Number of log entries to return. Clamped to 1-1000.
100ISO 8601 timestamp lower bound. Returns 400 if not parseable.
ISO 8601 timestamp upper bound. Returns 400 if not parseable.
Comma-separated list of service names to filter by.
Comma-separated list of severity levels to filter by (for example "INFO,WARN,ERROR").
Pass back next_cursor from the previous response to fetch the next page (older logs). Returns 400 if not parseable.
A page of logs.
Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
Rate limit exceeded. Most rate-limited responses are JSON; the device logs limiter can return a plain string response.
GET /{workspace}/devices/v2/{deviceId}/logs HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"data": [
{
"timestamp": "text",
"service": "text",
"severity": "text",
"message": "text"
}
],
"pagination": {
"next_cursor": "text",
"has_more": true,
"limit": 1
}
}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).
Example Response
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
Returns device health data: hardware metrics (CPU, memory, disk, GPU, network) bucketed across the requested time window, plus Docker and NTP health, per-service container status, per-stream FPS, hardware, and network interfaces. Rate-limited to 60 requests per minute per device with a 10-request burst over 10 seconds.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Time window to aggregate over.
24hPossible values: Comma-separated sections to return: metrics, system_status, services, service_history, stream_fps, hardware, network_interfaces. Every section except service_history is returned by default, and service_history implies services. Smaller requests return faster. An unknown section returns 400 with the valid values.
metrics,system_status,services,stream_fps,hardware,network_interfacesAggregated telemetry buckets.
Sections are selected with the include query parameter. Every section except service_history is returned by default.
Human-readable bucket size (for example "30 MINUTE", "4 HOUR").
Present when the service query hit its cap. Gaps in service history may come from the cap rather than a real outage.
Present when the stream FPS query hit its row cap, so some buckets are missing.
Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
Rate limit exceeded. Most rate-limited responses are JSON; the device logs limiter can return a plain string response.
GET /{workspace}/devices/v2/{deviceId}/telemetry HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"time_period": "1h",
"bucket_interval": "text",
"fill_interval_seconds": 1,
"buckets": [
{
"bucket_start": "2026-01-01T00:00:00.000Z",
"cpu_pct": 1,
"used_memory_mb": 1,
"total_memory_mb": 1,
"used_disk_space_mb": 1,
"total_disk_space_mb": 1,
"gpu_pct": 1,
"network_upload_bytes_per_sec": 1,
"network_download_bytes_per_sec": 1
}
],
"system_status": {
"docker": [
{
"bucket_start": "2026-01-01T00:00:00.000Z",
"status": "up",
"availability_pct": 1,
"version": "text",
"server": "text"
}
],
"ntp": [
{
"bucket_start": "2026-01-01T00:00:00.000Z",
"status": "up",
"availability_pct": 1,
"version": "text",
"server": "text"
}
]
},
"services": [
{
"name": "text",
"current_status": "up",
"latest": {
"container_id": "text",
"container_name": "text",
"image": "text",
"cpu_pct": 1,
"mem_usage_mb": 1,
"sample_count": 1,
"last_seen": "2026-01-01T00:00:00.000Z"
},
"history": [
{
"bucket_start": "2026-01-01T00:00:00.000Z",
"status": "text",
"cpu_pct": 1,
"mem_usage_mb": 1
}
]
}
],
"services_truncated": true,
"stream_fps": [
{
"pipeline_id": "text",
"stream_name": "text",
"stream_id": "text",
"buckets": [
{
"bucket_start": "2026-01-01T00:00:00.000Z",
"camera_fps": 1,
"inference_fps": 1
}
]
}
],
"stream_fps_truncated": true,
"hardware": {
"rfdm_version": "text",
"os_name": "text",
"os_version": "text",
"cpu_model": "text",
"cpu_cores": 1,
"jetson_model": "text",
"jetpack_version": "text",
"l4t_version": "text",
"jetson_power_mode": "text",
"nvidia_gpu": "text",
"nvidia_driver": "text",
"system_uptime_seconds": 1,
"ntp_server": "text",
"ntp_server_available": true,
"reported_at": "2026-01-01T00:00:00.000Z",
"additional": {
"ANY_ADDITIONAL_PROPERTY": "anything"
}
},
"network_interfaces": [
{
"name": "text",
"mac_address": "text",
"ip_addresses": [
"text"
]
}
],
"metadata": {
"data_points": 1,
"time_range": {
"start": "2026-01-01T00:00:00.000Z",
"end": "2026-01-01T00:00:00.000Z"
}
}
}Example Request
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
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
Returns device and stream lifecycle events (for example device boots, stream starts and stops, errors, config changes).
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Number of events to return. Clamped to 1-1000.
100Filter to events for a single entity type (for example "device", "stream").
Filter to events for a single entity ID.
Filter to events with this event name.
ISO 8601 timestamp lower bound. Returns 400 if not parseable.
ISO 8601 timestamp upper bound. Returns 400 if not parseable.
Opaque pagination cursor from a previous response. Pass back next_cursor or prev_cursor. Malformed cursors return 400.
Pagination direction. Other values return 400.
backwardPossible values: By default, events in a row that carry the same event name for the same entity collapse into one state change, unless the TTL of the earlier one has passed. That is right for lifecycle events and wrong for periodic telemetry, which reuses one event name for every sample. Set dedupe=false to read the raw rows. It needs both entity_type and entity_id, it reports event_end_timestamp as null, and it is rate-limited to 30 requests per minute per device.
trueA page of events.
Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
GET /{workspace}/devices/v2/{deviceId}/events HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"data": [
{
"id": "text",
"event": "text",
"entity_type": "text",
"entity_id": "text",
"event_description": "text",
"error_code": "text",
"metadata": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"device_timestamp": "text",
"server_timestamp": "text",
"event_end_timestamp": "text"
}
],
"pagination": {
"next_cursor": "text",
"prev_cursor": "text",
"has_more": true,
"limit": 1
}
}Example Request
Example Response
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.
By default the feed collapses repeated events into state changes, which hides periodic telemetry that reuses one event name. Pass dedupe=false with both entity_type and entity_id to read every raw row. To chart one value over time, use the service series endpoint instead: it resolves the entity ID for you.
Device Services
Returns the services a device runs, joined to their live status: container state, image version, and per-kind status such as PLC connection state or Event Store capacity.
Required scope: device:read
Returns the services a device runs and what each one is doing now. It joins the services declared in the device config with the same live status the Deployment Manager UI shows. Rate-limited to 30 requests per minute per device, in a bucket shared with the other service routes.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Comma-separated sections to return: status, config, signals, metrics. Only status is returned by default. Ask for config only when you need it: it returns environment variable values as stored, which often hold credentials. An unknown section returns 400 with the valid values.
statusReturn only services of this kind.
Window for the metrics section. Ignored otherwise.
24hPossible values: The device's services.
Present and true when the metrics aggregation hit its row cap. The newest rows are kept, so the oldest containers report metrics as null. Use a shorter time_period for full coverage.
Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
Rate limit exceeded. Most rate-limited responses are JSON; the device logs limiter can return a plain string response.
GET /{workspace}/devices/v2/{deviceId}/services HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"device_id": "text",
"services": [
{
"name": "plc-relay",
"kind": "plc_relay",
"image": "repo.roboflow.com/roboflow-edge/plc-relay",
"tag": "text",
"tag_is_canonical": true,
"automatic_updates": true,
"has_pending_changes": true,
"signal_conflicts": [
"text"
],
"state": "running",
"state_reported_at": "2026-01-01T00:00:00.000Z",
"state_received_at": "2026-01-01T00:00:00.000Z",
"error_code": "text",
"image_state": "pull_succeeded",
"image_state_reported_at": "2026-01-01T00:00:00.000Z",
"image_state_received_at": "2026-01-01T00:00:00.000Z",
"config": {
"ports": [
"text"
],
"volumes": [
"text"
],
"restart": "text",
"environment_variables": {
"ANY_ADDITIONAL_PROPERTY": "anything"
}
},
"status": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"signals": {
"ANY_ADDITIONAL_PROPERTY": {
"event": "plc_snapshot",
"event_description": "PLC connected, 2 tag(s)",
"error_code": "text",
"metadata": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"reported_at": "2026-01-01T00:00:00.000Z",
"received_at": "2026-01-01T00:00:00.000Z",
"ttl_s": 1,
"expired": true
}
},
"metrics": {
"current_status": "up",
"cpu_pct": 1,
"mem_usage_mb": 1,
"avg_cpu_pct": 1,
"avg_mem_usage_mb": 1,
"sample_count": 1,
"last_seen": "2026-01-01T00:00:00.000Z",
"last_received": "2026-01-01T00:00:00.000Z",
"last_reported_by_container": "2026-01-01T00:00:00.000Z"
}
}
],
"unassociated_signals": {
"ANY_ADDITIONAL_PROPERTY": {
"event": "plc_snapshot",
"event_description": "PLC connected, 2 tag(s)",
"error_code": "text",
"metadata": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"reported_at": "2026-01-01T00:00:00.000Z",
"received_at": "2026-01-01T00:00:00.000Z",
"ttl_s": 1,
"expired": true
}
},
"metrics_truncated": true
}Returns one service, in the same shape as an entry in the list. Returns 404 when the device declares no service with that name.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Service name, as declared in the device config.
Same sections as the list endpoint.
statusWindow for the metrics section. Ignored otherwise.
24hPossible values: One service.
One service declared on the device, joined to its live status. The config, status, signals, and metrics sections are returned only when you ask for them with the include parameter.
plc-relayService kind, resolved from the image. A container Roboflow does not publish resolves to "custom" and has no typed status.
plc_relayPossible values: repo.roboflow.com/roboflow-edge/plc-relayWhether the configured tag matches the version Roboflow ships for this service. Null when the service has no Roboflow-managed pin. This describes the config, not the running container.
True when a config edit is queued behind a maintenance window.
Entity IDs that more than one declared service claims. Signal IDs come from the service kind, so two services of the same kind collide unless each sets its own DEVICE_EVENT_ENTITY_ID. The status of an affected service is null because the reading cannot be attributed.
Container lifecycle state. Null when the last report is past its TTL, and also null when the service never reported. Use state_received_at to tell the two apart.
runningDevice clock. Null when the device sent no timestamp.
Server clock.
pull_succeededInvalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
Rate limit exceeded. Most rate-limited responses are JSON; the device logs limiter can return a plain string response.
GET /{workspace}/devices/v2/{deviceId}/services/{serviceName} HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"name": "plc-relay",
"kind": "plc_relay",
"image": "repo.roboflow.com/roboflow-edge/plc-relay",
"tag": "text",
"tag_is_canonical": true,
"automatic_updates": true,
"has_pending_changes": true,
"signal_conflicts": [
"text"
],
"state": "running",
"state_reported_at": "2026-01-01T00:00:00.000Z",
"state_received_at": "2026-01-01T00:00:00.000Z",
"error_code": "text",
"image_state": "pull_succeeded",
"image_state_reported_at": "2026-01-01T00:00:00.000Z",
"image_state_received_at": "2026-01-01T00:00:00.000Z",
"config": {
"ports": [
"text"
],
"volumes": [
"text"
],
"restart": "text",
"environment_variables": {
"ANY_ADDITIONAL_PROPERTY": "anything"
}
},
"status": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"signals": {
"ANY_ADDITIONAL_PROPERTY": {
"event": "plc_snapshot",
"event_description": "PLC connected, 2 tag(s)",
"error_code": "text",
"metadata": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"reported_at": "2026-01-01T00:00:00.000Z",
"received_at": "2026-01-01T00:00:00.000Z",
"ttl_s": 1,
"expired": true
}
},
"metrics": {
"current_status": "up",
"cpu_pct": 1,
"mem_usage_mb": 1,
"avg_cpu_pct": 1,
"avg_mem_usage_mb": 1,
"sample_count": 1,
"last_seen": "2026-01-01T00:00:00.000Z",
"last_received": "2026-01-01T00:00:00.000Z",
"last_reported_by_container": "2026-01-01T00:00:00.000Z"
}
}Use these endpoints to poll a fleet: ask for include=status to check that a service is up and reporting, and add include=metrics for its CPU and memory.
Services report telemetry under an entity ID that comes from the service kind. Two services of the same kind on one device therefore collide unless you give each its own DEVICE_EVENT_ENTITY_ID. When that happens, the API lists the shared IDs in signal_conflicts and returns status as null, because it cannot tell which container sent the reading. A custom entity ID must use only letters, digits, hyphens, and underscores. The characters ., /, *, ~, [, and ] break the status cache, and the service then reports no status at all.
Service Metric Series
Returns one metric for one service over time, for charting.
Returns one named metric for one service over time, for charting. The metric name resolves to the right entity ID and event names for that service kind, and every raw sample is returned with no deduplication. The time_period selects samples by when Roboflow received them, so a device with a wrong clock still returns its current data. Returns 409 when another service of the same kind claims the same entity ID.
Roboflow API key passed as a Bearer token.
Workspace ID (URL slug).
Device ID.
Service name, as declared in the device config.
Metric to return. Metric names depend on the service kind (ex: connected for plc_relay; records, bytes_percent for event_store). An unknown name returns 400 that lists the valid names for that kind.
Window to read.
24hPossible values: The metric over time.
plc-relayplc_relayconnectedA boolean metric charts as 1 or 0. The type is echoed so a 1 that means "true" stays readable as one.
24hTrue when the window held more than 5,000 samples. The newest samples are kept, so covered_from and covered_to can cover less than the requested time_period.
Invalid query parameter or request body.
Missing or invalid API key.
API key is bound to a different device, or this endpoint is not permitted for device-scoped keys, a source device belongs to another workspace, or a feature gate (for example AI1 creation, roboflowLiteMode) blocks the request.
Device, stream, configuration, or source device not found. Read requests for devices owned by another workspace also return 404.
Two services of the same kind report under the same entity ID.
Rate limit exceeded. Most rate-limited responses are JSON; the device logs limiter can return a plain string response.
GET /{workspace}/devices/v2/{deviceId}/services/{serviceName}/series?metric=text HTTP/1.1
Host: api.roboflow.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"device_id": "text",
"service": "plc-relay",
"kind": "plc_relay",
"metric": "connected",
"metric_type": "number",
"time_period": "24h",
"available_metrics": [
"text"
],
"truncated": true,
"covered_from": "2026-01-01T00:00:00.000Z",
"covered_to": "2026-01-01T00:00:00.000Z",
"points": [
{
"timestamp": "2026-01-01T00:00:00.000Z",
"value": 1
}
]
}Metric names depend on the service kind. Call it with an unknown metric and the 400 response lists the valid names in valid_values.
event_store
records, records_percent, images, bytes_used, bytes_percent, backed_up_records, backed_up_bytes_percent, pending_records, pending_bytes, draft_records, oldest_draft_age_seconds, disk_percent_used
plc_relay
connected
opcua_server
session_count, refused_total
rtsp_simulator, device_hmi, custom
None. These report container state and metrics only.
MCP Server
Connect your AI agent to the MCP Server and it can check on an edge device with these tools:
devices_list
List devices registered in the workspace.
devices_get_snapshot
Get the full current state of a device in one call.
devices_get_config
Get the device's current runtime configuration.
devices_update_config
Update the device's runtime configuration.
devices_streams_list
List streams configured on the device.
devices_get_logs
Fetch device logs.
devices_get_telemetry
Get aggregated hardware metrics and device health.
Last updated
Was this helpful?