LitmusEdge 4.0.x API Documentation/DeviceHub/Devices - LE, LEM, LUNS API Docs
List Devices
POST {{edgeUrl}}/devicehub/v2
List Devices
Returns every configured device in DeviceHub along with the most commonly needed fields. This is the richer projection used by the LE UI's device list and by automation that needs to enumerate devices and their parameters in one call.
For a minimal (ID + Name) projection used by the dashboard tile, see Dashboard > List of Devices.
Endpoint
POST {{edgeUrl}}/devicehub/v2
Content-Type: application/json
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Request body (GraphQL)
query ListDevices {
ListDevices {
ID
Name
DriverID
AliasTopics
CreationTime
Description
WorkerParams {
Name
Value
Description
}
DHParams {
Name
Value
Description
}
}
}
ListDevices accepts an optional input: { IDs: [ID!] } filter (omit to return every device). Any field on Device can be added to the selection, including Properties, MetaData, Topics, StatusPollingRegister, StoppedState, Debug.
Response
200 OK -- application/json
| Field | GraphQL type | Description |
|---|---|---|
ID |
ID |
Device UUID. Used as {{deviceID}} in REST endpoints and as the foreign key from tags/registers. |
Name |
String |
Display name of the device. Must be unique across the device list. |
DriverID |
ID |
UUID of the driver template bound to this device. Not re-assignable; create a new device to change drivers. |
AliasTopics |
Boolean |
true means published MQTT topics use the human-readable register name; false means the raw register key. |
CreationTime |
Time |
ISO 8601 timestamp the device was created. 1970-01-01T00:00:00Z for devices created before this field was introduced. |
Description |
String |
Free-form description set by the operator. |
WorkerParams |
[Param!]! |
Internal worker tunables (poll interval, batching, etc.). Each entry has Name, Value, Description. |
DHParams |
[Param!]! |
DeviceHub-level parameters, same {Name,Value,Description} shape. Driver-agnostic settings. |
Example response
{
"data": {
"ListDevices": [
{
"ID": "41FBD12E-C6CD-4539-AD50-336D278B207C",
"Name": "Rack 2b M258",
"DriverID": "2AF1FA08-D638-11E9-BB65-2A2AE2DBCCE4",
"AliasTopics": false,
"CreationTime": "1970-01-01T00:00:00Z",
"Description": "",
"WorkerParams": [
{
"Name": "PublishOnPollingInterval",
"Value": "true",
"Description": "true"
}
],
"DHParams": []
}
]
}
}
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
query ListDevices {
ListDevices {
ID
Name
DriverID
AliasTopics
CreationTime
Description
WorkerParams {
Name
Value
Description
}
DHParams {
Name
Value
Description
}
}
}
Response
Status: 200 OK
{
"data": {
"ListDevices": [
{
"ID": "41FBD12E-C6CD-4539-AD50-336D278B207C",
"Name": "Rack 2b M258",
"DriverID": "2AF1FA08-D638-11E9-BB65-2A2AE2DBCCE4",
"AliasTopics": false,
"CreationTime": "1970-01-01T00:00:00Z",
"Description": "",
"WorkerParams": [
{
"Name": "PublishOnPollingInterval",
"Value": "true",
"Description": "true"
}
],
"DHParams": [
{
"Name": "WatchDogPeriod",
"Value": "30",
"Description": "30"
},
{
"Name": "WatchDog",
"Value": "true",
"Description": "true"
}
]
}
]
}
}
Create New Device
POST {{edgeUrl}}/devicehub/v2
Create New Device
Creates a single device bound to a driver template. The Properties array supplies the values for every property declared by the driver, and any property the driver marks as Required must be present here. The returned ID is the canonical device UUID used in every subsequent call.
Set StoppedState: true if you want the device to be created but not attempt to connect yet -- useful when you are programmatically populating properties or want to attach registers before the first poll. To start the device later, call Start Device.
Endpoint
POST {{edgeUrl}}/devicehub/v2
Content-Type: application/json
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Request body (GraphQL)
mutation CreateDevice($input: CreateDeviceRequest!) {
CreateDevice(input: $input) {
ID
Name
DriverID
Description
}
}
Variables (input: CreateDeviceRequest!)
| Field | Type | Required | Description |
|---|---|---|---|
DriverID |
ID |
Yes | UUID of the driver template. List drivers via DeviceHub > Drivers > List Drivers. |
Name |
String |
Yes | Display name. Must be unique across all devices. |
Properties |
[KeyValueInput!]! |
Yes | Driver-defined property values. Each entry is {Key, Value}. Required properties depend on the driver -- see the driver's template via DeviceHub > Drivers > Get Driver. |
Description |
String |
No | Free-form description shown in the UI. |
AliasTopics |
Boolean |
No | Default false. true makes published MQTT topics use the human register name instead of the raw key. |
Debug |
Boolean |
No | Default false. Enables verbose driver logging for this device. |
MetaData |
[KeyValueInput!] |
No | Operator-controlled metadata (e.g. vendor, model, fw_ver). Surfaced in the UI and downstream pipelines. |
StatusRegister |
RegisterInput |
No | Register definition whose value DeviceHub treats as the device's connection-status signal. null disables. |
StoppedState |
Boolean |
No | Default false. true creates the device in a stopped state -- no connection attempt until Start Device. |
Variables (example)
{
"input": {
"DriverID": "5BC98836-CFD4-11E9-BB65-2A2AE2DBCCE4",
"Name": "apiTestDevice",
"Description": "deviceCreatedfromAPI",
"AliasTopics": true,
"Debug": false,
"MetaData": [],
"Properties": [
{ "Key": "name", "Value": "apiTestDevice" },
{ "Key": "description", "Value": "deviceCreatedfromAPI" }
],
"StatusRegister": null,
"StoppedState": false
}
}
Response
200 OK -- application/json
| Field | Type | Description |
|---|---|---|
data.CreateDevice.ID |
ID |
UUID of the newly created device. Save this as {{deviceID}}. |
data.CreateDevice.Name |
String |
Device name echoed back. |
data.CreateDevice.DriverID |
ID |
Driver UUID echoed back. |
data.CreateDevice.Description |
String |
Description echoed back. |
{
"data": {
"CreateDevice": {
"ID": "36B0FDFA-AFC8-4B84-B0B0-296893DB18ED",
"Name": "apiTestDevice",
"DriverID": "5BC98836-CFD4-11E9-BB65-2A2AE2DBCCE4",
"Description": ""
}
}
}
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
Common BAD_USER_INPUT causes
DriverIDdoes not match any installed driver.- A required property for the driver is missing from
Properties. - A property value fails the driver's type/regex constraints (e.g. a port number outside
0..65535, an enum value not inListValues). Namecollides with an existing device.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
mutation CreateDevice($input: CreateDeviceRequest!) {
CreateDevice(input: $input) {
ID
Name
DriverID
Description
}
}
Variables
{
"input": {
"AliasTopics": true,
"Debug": false,
"MetaData": [],
"Name": "apiTestDevice",
"Description": "",
"Properties": [
{
"Key": "name",
"Value": "apiTestDevice"
},
{
"Key": "description",
"Value": "deviceCreatedfromAPI"
}
],
"StatusRegister": null,
"StoppedState": false,
"DriverID": "5BC98836-CFD4-11E9-BB65-2A2AE2DBCCE4"
}
}
Response
Status: 200 OK
{
"data": {
"CreateDevice": {
"ID": "36B0FDFA-AFC8-4B84-B0B0-296893DB18ED",
"Name": "apiTestDevice",
"DriverID": "5BC98836-CFD4-11E9-BB65-2A2AE2DBCCE4",
"Description": ""
}
}
}
Update Device
POST {{edgeUrl}}/devicehub/v2
Update Device
Replaces the mutable fields of an existing device. Update Device is a full replacement of the input shape, not a JSON-patch: every value you include is written, every value you omit is left at its server-side default. Provide the full Properties array even when changing a single key, otherwise unspecified keys are reset.
Use this to:
- Re-key the device (
Name). - Re-target a different host (
Properties->networkAddress,networkPort, etc.). - Toggle
DebugorAliasTopics. - Refresh
MetaDatasuch asvendor,model,fw_ver. - Reassign the
StatusRegisterused to compute the device's online/offline state.
You cannot change DriverID. To switch drivers, delete the device and create a new one with the desired driver.
Endpoint
POST {{edgeUrl}}/devicehub/v2
Content-Type: application/json
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Request body (GraphQL)
mutation UpdateDevice($input: UpdateDeviceRequest!) {
UpdateDevice(input: $input) {
ID
Name
DriverID
Description
Debug
Properties { Name Value Description }
Topics { Direction Encoding Format IntervalMs Topic }
MetaData { Name Value Description }
AliasTopics
CreationTime
StatusPollingRegister {
Name
ValueType
Properties { Name Value Description }
}
}
}
The selection set in the response is yours to choose; the example above mirrors the LE UI's projection.
Variables (input: UpdateDeviceRequest!)
| Field | Type | Required | Description |
|---|---|---|---|
ID |
ID |
Yes | UUID of the device to update. |
Name |
String |
Yes | New name. Must remain unique across devices. |
Description |
String |
No | Free-form description. |
Properties |
[KeyValueInput!]! |
Yes | Full driver property set. Send the complete list -- omitted keys are not preserved. |
MetaData |
[KeyValueInput!] |
No | Operator metadata. Same semantics as Properties: it is a full replacement. |
AliasTopics |
Boolean |
No | See Create New Device. |
Debug |
Boolean |
No | See Create New Device. |
StatusRegister |
RegisterInput |
No | Reassign the status register. null removes it. |
Variables (example)
{
"input": {
"ID": "41FBD12E-C6CD-4539-AD50-336D278B207C",
"Name": "Rack 2b M258",
"Description": "Modbus TCP Ethernet Driver",
"AliasTopics": false,
"Debug": false,
"MetaData": [
{ "Key": "device_type", "Value": "PLC" },
{ "Key": "fw_ver", "Value": "v2.0.31.40" },
{ "Key": "model", "Value": "modicon m258" },
{ "Key": "vendor", "Value": "schneider electric" },
{ "Key": "device_mac_addr", "Value": "00:80:f4:41:20:68" }
],
"Properties": [
{ "Key": "name", "Value": "Rack 2b M258" },
{ "Key": "description", "Value": "Modbus TCP Ethernet Driver" },
{ "Key": "networkAddress", "Value": "10.17.0.8" },
{ "Key": "networkPort", "Value": "502" },
{ "Key": "stationId", "Value": "1" },
{ "Key": "Zero-Based Addressing", "Value": "1" }
],
"StatusRegister": null
}
}
Response
200 OK -- application/json. Echoes the new state of the device using the selection set from the request. Server-side defaults are filled in for any optional field you left out.
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
Operational note
Updating connection-relevant Properties (host, port, credentials) does not automatically restart the device worker. If the device is already started, the worker is signaled to reconnect; for major topology changes (e.g. switching transport) consider an explicit Stop Device -> update -> Start Device sequence to avoid stale connections.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
mutation UpdateDevice($input: UpdateDeviceRequest!) {
UpdateDevice(input: $input) {
ID
Name
DriverID
Description
Debug
Properties {
Name
Value
Description
}
Topics {
Direction
Encoding
Format
IntervalMs
Topic
}
MetaData {
Name
Value
Description
}
AliasTopics
CreationTime
StatusPollingRegister {
Name
ValueType
Properties {
Name
Value
Description
}
}
}
}
Variables
{
"input": {
"AliasTopics": false,
"Debug": false,
"MetaData": [
{
"Key": "device_type",
"Value": "PLC"
},
{
"Key": "fw_ver",
"Value": "v2.0.31.40"
},
{
"Key": "model",
"Value": "modicon m258"
},
{
"Key": "vendor",
"Value": "schneider electric"
},
{
"Key": "version",
"Value": "schneider modocon 1.01"
},
{
"Key": "device_mac_addr",
"Value": "00:80:f4:41:20:68"
}
],
"Name": "Rack 2b M258",
"Description": "Modbus TCP Ethernet Driver",
"Properties": [
{
"Key": "name",
"Value": "Rack 2b M258"
},
{
"Key": "description",
"Value": "Modbus TCP Ethernet Driver"
},
{
"Key": "networkAddress",
"Value": "10.17.0.8"
},
{
"Key": "networkPort",
"Value": "502"
},
{
"Key": "stationId",
"Value": "1"
},
{
"Key": "Zero-Based Addressing",
"Value": "1"
}
],
"StatusRegister": null,
"ID": "41FBD12E-C6CD-4539-AD50-336D278B207C"
}
}
Response
Status: 200 OK
{
"data": {
"UpdateDevice": {
"ID": "41FBD12E-C6CD-4539-AD50-336D278B207C",
"Name": "Rack 2b M258",
"DriverID": "2AF1FA08-D638-11E9-BB65-2A2AE2DBCCE4",
"Description": "",
"Debug": false,
"Properties": [
{
"Name": "description",
"Value": "Modbus TCP Ethernet Driver",
"Description": "Modbus TCP Ethernet Driver"
},
{
"Name": "name",
"Value": "Rack 2b M258",
"Description": "Rack 2b M258"
},
{
"Name": "Zero-Based Addressing",
"Value": "1",
"Description": "1"
},
{
"Name": "stationId",
"Value": "1",
"Description": "1"
},
{
"Name": "networkPort",
"Value": "502",
"Description": "502"
},
{
"Name": "networkAddress",
"Value": "10.17.0.8",
"Description": "10.17.0.8"
}
],
"Topics": [
{
"Direction": "Output",
"Encoding": "JSON",
"Format": "Raw",
"IntervalMs": null,
"Topic": "devicehub.plcstatus.41FBD12E-C6CD-4539-AD50-336D278B207C"
},
{
"Direction": "Input",
"Encoding": "JSON",
"Format": "Command",
"IntervalMs": null,
"Topic": "devicehub.manage.41FBD12E-C6CD-4539-AD50-336D278B207C"
},
{
"Direction": "Output",
"Encoding": "JSON",
"Format": "Raw",
"IntervalMs": null,
"Topic": "devicehub.raw.41FBD12E-C6CD-4539-AD50-336D278B207C.>"
}
],
"MetaData": [
{
"Name": "device_type",
"Value": "PLC",
"Description": "PLC"
},
{
"Name": "device_mac_addr",
"Value": "00:80:f4:41:20:68",
"Description": "00:80:f4:41:20:68"
},
{
"Name": "version",
"Value": "schneider modocon 1.01",
"Description": "schneider modocon 1.01"
},
{
"Name": "vendor",
"Value": "schneider electric",
"Description": "schneider electric"
},
{
"Name": "model",
"Value": "modicon m258",
"Description": "modicon m258"
},
{
"Name": "fw_ver",
"Value": "v2.0.31.40",
"Description": "v2.0.31.40"
}
],
"AliasTopics": false,
"CreationTime": "1970-01-01T00:00:00Z",
"StatusPollingRegister": null
}
}
}
Enable/Disable Device Data Storage
PUT {{edgeUrl}}/stats/devices/{{deviceID}}
Enable/Disable Device Data Storage
Controls whether DeviceHub persists telemetry from this device to the on-device time-series store. This is the same setting exposed by the Data Storage toggle on the device page in the LE UI.
When saveAll is false, no tag values from this device are persisted (the device still publishes to MQTT/integrations in real time). When true, DeviceHub writes to the local store and retains data for retentionHours, rotating older points out.
This endpoint is REST -- the underlying stats service is not part of the DeviceHub GraphQL surface.
Endpoint
PUT {{edgeUrl}}/stats/devices/{{deviceID}}
Content-Type: application/json
{{deviceID}} is the UUID of the target device. Both the path parameter and the body include the ID; they must match.
Authentication
HTTP Basic Auth. Username is your API token, password is empty. Tokens are managed under System > Access Control > Tokens.
Request body
{
"ID": "{{deviceID}}",
"name": "boiler-01",
"retentionHours": 12,
"saveAll": false
}
| Field | Type | Required | Description |
|---|---|---|---|
ID |
string | Yes | Device UUID. Must match the path parameter. |
name |
string | Yes | Device name. The stats service stores this alongside the ID; pass the current name. |
retentionHours |
integer | Yes | How many hours of data to keep. 0 disables retention even if saveAll: true. |
saveAll |
boolean | Yes | true enables persistence of all of the device's tags; false disables. |
Response
200 OK on success, with an empty body or a small JSON ack depending on build. The change applies immediately to the running worker -- no restart required.
Errors
| HTTP status | When it happens |
|---|---|
400 Bad Request |
Body is missing a required field, or ID in body does not match path. |
401 Unauthorized |
Missing or invalid credentials. |
403 Forbidden |
Token lacks write access to the stats service. |
404 Not Found |
No device exists with the given ID. |
502 / 503 |
Stats service is not running. |
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
{
"ID": "{{deviceID}}",
"name": "boiler-01",
"retentionHours": 12,
"saveAll": false
}
Response
Status: 204 No Content
Delete Devices graphQL
POST {{edgeUrl}}/devicehub/v2
Delete Devices (GraphQL, bulk)
Deletes one or more devices in a single mutation. The operation is bulk by design -- pass a single-element IDs array to delete one device, or a list to delete many atomically.
Deletes cascade to the device's registers/tags, examples in DeviceHub > Tags, and any topic subscriptions tied to the device. They do not delete time-series data already persisted to the stats store; those points age out via the retention policy configured on the stats service.
For a single-device REST equivalent (path-parameter style), see Delete Device Rest.
Endpoint
POST {{edgeUrl}}/devicehub/v2
Content-Type: application/json
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Request body (GraphQL)
mutation DeleteDevices($input: DeleteDevicesRequest!) {
DeleteDevices(input: $input)
}
Variables (input: DeleteDevicesRequest!)
| Field | Type | Required | Description |
|---|---|---|---|
IDs |
[ID!]! |
Yes | UUIDs of devices to delete. Unknown IDs are ignored (no per-ID error report). |
Variables (example)
{
"input": {
"IDs": [
"4F2715FE-4B84-4223-AFA6-858504803ED7",
"8CDACA9A-FF14-482B-B1A0-F85700525980"
]
}
}
Response
200 OK -- application/json. The mutation returns no data on success.
{
"data": {
"DeleteDevices": null
}
}
A null payload indicates the delete succeeded for the IDs that existed; silently-ignored unknown IDs do not surface as errors here. To confirm a specific device was removed, follow up with List Devices or Get Device.
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
mutation DeleteDevices ($input : DeleteDevicesRequest!) {
DeleteDevices(input: $input)
}
Variables
{
"input": {
"IDs": [
"4F2715FE-4B84-4223-AFA6-858504803ED7",
"8CDACA9A-FF14-482B-B1A0-F85700525980"
]
}
}
Response
Status: 200 OK
{
"data": {
"DeleteDevices": null
}
}
Delete Device Rest
DELETE {{edgeUrl}}/devicehub/devices/{{deviceID}}
Delete Device (REST, single)
Deletes a single device identified by path parameter. This is the REST equivalent of Delete Devices graphQL with a one-element IDs array. The GraphQL form is preferred for new automation -- this REST endpoint exists mainly for legacy clients.
Side effects are identical to the GraphQL form: the device's registers, topic subscriptions, and configuration are removed. Persisted time-series data ages out via the stats retention policy.
Endpoint
DELETE {{edgeUrl}}/devicehub/devices/{{deviceID}}
{{deviceID}} is the UUID of the device to delete.
Authentication
HTTP Basic Auth. Username is your API token, password is empty. Tokens are managed under System > Access Control > Tokens.
Parameters
| Location | Name | Required | Description |
|---|---|---|---|
| Path | {{deviceID}} |
Yes | UUID of the device to delete. |
No request body.
Response
200 OK with an empty body on success.
Errors
| HTTP status | When it happens |
|---|---|
401 Unauthorized |
Missing or invalid credentials. |
403 Forbidden |
Token lacks delete access to DeviceHub. |
404 Not Found |
No device exists with the given ID. (The GraphQL form silently ignores; this one surfaces a 404.) |
502 / 503 |
DeviceHub service is unreachable. |
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Response
Status: 204 No Content
Device Discovery Tool
POST {{edgeUrl}}/devicehub/v2
Device Discovery Tool
Asks a driver to enumerate discoverable endpoints/servers reachable from its configured network neighborhood, without creating a device first. The returned DiscoveryOptions array is a menu of pre-filled property bundles the operator can pick from to spawn a device.
This feature is only available for protocols that support discovery. As of LE 4.0 those are:
- BACnet (the
BacnetIPdriver) - OPC UA (the
OPC UA Client Advanceddriver)
Other drivers return an empty DiscoveryOptions array.
Endpoint
POST {{edgeUrl}}/devicehub/v2
Content-Type: application/json
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Request body (GraphQL)
query Discovery($input: DiscoveryRequest!) {
Discovery(input: $input) {
DiscoveryOptions {
Label
Description
Fields {
Name
Type
Value
}
}
}
}
Variables (input: DiscoveryRequest!)
| Field | Type | Required | Description |
|---|---|---|---|
DriverID |
ID |
Yes | UUID of a discovery-capable driver (BACnet or OPC UA Advanced). |
Properties |
[KeyValueInput!]! |
Yes | Driver-specific seed properties controlling the search scope. For OPC UA, this is the discovery/server URL; for BACnet, the local interface and address range. |
Variables (example, OPC UA)
{
"input": {
"DriverID": "2372E68F-BA1B-46E9-BC07-E92CA006B377",
"Properties": [
{
"Key": "Discovery Server URL (Servers and Endpoints Discovery)",
"Value": "opc.tcp://localhost:4840"
},
{
"Key": "Server URL (Endpoints Discovery)",
"Value": "opc.tcp://10.17.2.198:53530/OPCUA/SimulationServer"
}
]
}
}
The exact Keys depend on the driver. List the supported keys via DeviceHub > Drivers > Get Driver and inspect the driver template's discovery-related properties.
Response
200 OK -- application/json
| Field | Type | Description |
|---|---|---|
data.Discovery.DiscoveryOptions |
[Option!]! |
Menu of discovered endpoints. Empty array means no devices/endpoints found. |
data.Discovery.DiscoveryOptions[].Label |
String |
Human-readable name (e.g. SimulationServer@DESKTOP - opc.tcp://...). |
data.Discovery.DiscoveryOptions[].Description |
String |
Free-form annotation, often security policy/mode for OPC UA. |
data.Discovery.DiscoveryOptions[].Fields |
[Field!]! |
Pre-filled property values for this option. Pass these as Properties to Create New Device to spawn the device. |
data.Discovery.DiscoveryOptions[].Fields[].Name |
String |
Property key. |
data.Discovery.DiscoveryOptions[].Fields[].Type |
String |
Type hint (String, Int, enum index, etc.). Often null for free-text values. |
data.Discovery.DiscoveryOptions[].Fields[].Value |
String |
Property value to copy into the new device. |
Example response
{
"data": {
"Discovery": {
"DiscoveryOptions": [
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Basic256Sha256, Security Mode: Sign",
"Fields": [
{ "Name": "SecurityPolicy", "Type": null, "Value": "3" },
{ "Name": "ServerURL", "Type": null, "Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer" }
]
}
]
}
}
}
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
Discovery-specific errors
BAD_USER_INPUTwithDriverID is not discoverable: the driver does not support discovery (only BACnet and OPC UA Advanced do).INTERNAL_SERVER_ERRORwith a timeout: the discovery scope was too wide or the upstream server did not respond. Narrow the URL or address range.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
query Discovery($input: DiscoveryRequest!) {
Discovery(input: $input) {
DiscoveryOptions {
Label
Description
Fields {
Name
Type
Value
}
}
}
}
Variables
{
"input": {
"DriverID": "2372E68F-BA1B-46E9-BC07-E92CA006B377",
"Properties": [
{
"Key": "Discovery Server URL (Servers and Endpoints Discovery)",
"Value": "opc.tcp://localhost:4840"
},
{
"Key": "Server URL (Endpoints Discovery)",
"Value": "opc.tcp://10.17.2.198:53530/OPCUA/SimulationServer"
}
]
}
}
Response
Status: 200 OK
{
"data": {
"Discovery": {
"DiscoveryOptions": [
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Basic256Sha256, Security Mode: Sign",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "3"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "1"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Basic128Rsa15, Security Mode: SignAndEncrypt",
"Fields": [
{
"Name": "SecurityMode",
"Type": null,
"Value": "2"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
},
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "1"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Aes256Sha256RsaPss, Security Mode: SignAndEncrypt",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "5"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "2"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Basic128Rsa15, Security Mode: Sign",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "1"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "1"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Aes256Sha256RsaPss, Security Mode: Sign",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "5"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "1"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Basic256Sha256, Security Mode: SignAndEncrypt",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "3"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "2"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: None, Security Mode: None",
"Fields": [
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
},
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "0"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "0"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Aes128Sha256RsaOaep, Security Mode: Sign",
"Fields": [
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
},
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "4"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "1"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Basic256, Security Mode: SignAndEncrypt",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "2"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "2"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Basic256, Security Mode: Sign",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "2"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "1"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
}
]
},
{
"Label": "SimulationServer@DESKTOP-IRI8PIH - opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer",
"Description": "Security Policy: Aes128Sha256RsaOaep, Security Mode: SignAndEncrypt",
"Fields": [
{
"Name": "SecurityPolicy",
"Type": null,
"Value": "4"
},
{
"Name": "SecurityMode",
"Type": null,
"Value": "2"
},
{
"Name": "ServerURL",
"Type": null,
"Value": "opc.tcp://DESKTOP-IRI8PIH:53530/OPCUA/SimulationServer"
}
]
}
]
}
}
}
Device Connection Status
POST {{edgeUrl}}/devicehub/v2
Device Connection Status (subscription)
Streams real-time updates whenever any device's connection state changes (connected, disconnected, reconnecting, error, ...). This is a GraphQL subscription, not a query -- it is designed for clients that hold an open connection and receive a push for every event, not for polling.
The LE UI uses this to live-update the green/red status dots on the device list. Use it from your own dashboards or alerting pipelines for sub-second reactions to device state changes.
Transport
Subscriptions require a long-lived transport. A plain POST to {{edgeUrl}}/devicehub/v2 will return only the first event (or none) and then close. The supported transports are:
| Transport | Path | Notes |
|---|---|---|
WebSocket (graphql-ws) |
wss://{{edgeHost}}/devicehub/v2 |
Preferred. Use subscriptions-transport-ws or graphql-ws on the client. |
Server-Sent Events (SSE) |
{{edgeUrl}}/devicehub/v2 with Accept: text/event-stream |
Best for one-way browser clients without a WS library. |
The Postman item is shown as a POST for documentation and one-shot testing; switch to a Postman WebSocket request (Files > New > WebSocket Request) when you need the streaming behavior.
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Subscription body
subscription DeviceChanged {
DeviceChanged {
DevStatus
DeviceID
}
}
DeviceChanged accepts no arguments and fires for every device. To distinguish events, branch on DeviceID client-side.
Available fields
Selectable fields on DeviceChanged include all of:
| Field | Type | Description |
|---|---|---|
DeviceID |
ID |
UUID of the device whose state changed. |
DevStatus |
String |
New connection state. Common values: Connected, Disconnected, Reconnecting, Error, Starting, Stopped. |
Event shape
Each event has the same data-wrapped shape as a query response:
{
"data": {
"DeviceChanged": {
"DevStatus": "Connected",
"DeviceID": "79F3914E-32A1-4227-AC16-023E627EB26E"
}
}
}
A burst of Reconnecting followed by Connected is normal after network flaps; treat the most recent event as the source of truth.
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
Subscription-specific notes
- If the transport closes unexpectedly, reconnect with backoff. There is no replay or "missed events" buffer -- events that occur while you are disconnected are lost.
- On reconnect, also issue
List Devicesto reconcile state.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
subscription DeviceChanged {
DeviceChanged {
DevStatus
DeviceID
}
}
Response
Status: 200 OK
{
"data": {
"DeviceChanged": {
"DevStatus": "Connected",
"DeviceID": "79F3914E-32A1-4227-AC16-023E627EB26E"
}
}
}
Start Device
POST {{edgeUrl}}/devicehub/v2
Start Device
Starts the worker for one or more devices. After StartDevices returns, the device begins polling/connecting and DeviceChanged events will flow for it.
Idempotent for already-running devices -- starting a running device is a no-op and does not return an error.
Endpoint
POST {{edgeUrl}}/devicehub/v2
Content-Type: application/json
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Request body (GraphQL)
mutation StartDevices($input: StartDevicesRequest!) {
StartDevices(input: $input)
}
Variables (input: StartDevicesRequest!)
| Field | Type | Required | Description |
|---|---|---|---|
IDs |
[ID!]! |
Yes | UUIDs of devices to start. Pass a single-element array for one device. |
Variables (example)
{
"input": {
"IDs": ["{{deviceID}}"]
}
}
Response
200 OK -- application/json. The mutation returns no data on success.
{
"data": {
"StartDevices": null
}
}
A null payload means the start was accepted by DeviceHub. It does not mean the device is connected yet -- subscribe to Device Connection Status or poll List Devices to observe the transition from Starting to Connected.
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
mutation StartDevices($input: StartDevicesRequest!) {
StartDevices(input: $input)
}
Variables
{
"input": {
"IDs": [
"{{deviceID}}"
]
}
}
Response
Status: 200 OK
{
"data": {
"StartDevices": null
}
}
Stop Device
POST {{edgeUrl}}/devicehub/v2
Stop Device
Stops the worker for one or more devices. The device disconnects from its upstream system, stops polling, and stops publishing to integrations. Its configuration remains intact -- use Start Device to resume, or Delete Devices graphQL to remove permanently.
Idempotent for already-stopped devices.
Endpoint
POST {{edgeUrl}}/devicehub/v2
Content-Type: application/json
Authentication
HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.
Request body (GraphQL)
mutation StopDevices($input: StopDevicesRequest!) {
StopDevices(input: $input)
}
The Postman item names the operation StopDevicesRequest for legacy reasons; the GraphQL operation name is StopDevices and what matters at the server is the field name in the selection set.
Variables (input: StopDevicesRequest!)
| Field | Type | Required | Description |
|---|---|---|---|
IDs |
[ID!]! |
Yes | UUIDs of devices to stop. Pass a single-element array for one device. |
Variables (example)
{
"input": {
"IDs": ["{{deviceID}}"]
}
}
Response
200 OK -- application/json. The mutation returns no data on success.
{
"data": {
"StopDevices": null
}
}
The device transitions through Stopping to Stopped. To observe the transition in real time, subscribe to Device Connection Status.
Errors
GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:
{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code |
Meaning |
|---|---|
UNAUTHENTICATED |
Missing or invalid API token. |
FORBIDDEN |
Token lacks permission for this operation. |
BAD_USER_INPUT |
Invalid argument (wrong type, missing required field, malformed UUID, unknown DriverID, etc.). |
NOT_FOUND |
The targeted device, driver, or related entity does not exist. |
INTERNAL_SERVER_ERROR |
DeviceHub fault. Retry, then escalate via System > Support. |
A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.
TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.
Request Body
GraphQL Query
mutation StopDevicesRequest($input: StopDevicesRequest!) {
StopDevices(input: $input)
}
Variables
{
"input": {
"IDs": [
"{{deviceID}}"
]
}
}
Response
Status: 200 OK
{
"data": {
"StopDevices": null
}
}