Guide

REST agent

Turns plain HTTP POSTs into SCADA measurements — the driver address, the two ingest endpoints, and the docker image's own config.

This is the protocol reference for the REST agent. For a guided walkthrough — create the agent, upload a config, watch it live — see Connect a REST agent. For everything else in the config format — alarms, commands, interlocks, value conversion — see Agent configuration.

01
Driver address

driver.path is a string you choose — there's no fixed format. It's both the measurement's join key in the config and the URL segment the agent listens on, so pick whatever's convenient: sequential numbers, register addresses, your own naming scheme.

measurement
{
  "name": "brk_10",
  "equipment": "eqp",
  "type": "discrete",
  "store": true,
  "driver": { "type": "discrete", "path": "1" }
}
Endpoints

POST /addr/{path} — submit one measurement, where {path} matches a configured driver.path:

  • value — required, a number. Whether it lands as discrete or analogical follows the measurement's configured type.
  • timestamp — optional, RFC 3339. Defaults to the current time.
  • quality — optional, boolean. true (the default) is Good, false is Bad.
shellshell
curl -X POST http://localhost:9090/addr/1 \
  -H "Content-Type: application/json" \
  -d '{
    "value": 2,
    "timestamp": "2025-02-16T21:52:13Z",
    "quality": true
  }'

Returns 404 if {path} isn't configured.

POST /batch — the same, for a JSON array. Each entry carries its own addr instead of putting it in the URL:

shellshell
curl -X POST http://localhost:9090/batch \
  -H "Content-Type: application/json" \
  -d '[
    { "addr": "1", "value": 10 },
    { "addr": "2", "value": 11.5, "quality": false }
  ]'

GET /health — liveness check, returns Healthy!.

Commands

The REST agent doesn't know how to reach your equipment on its own — set rest.webhook in its own config (below), and every command sent to this agent is forwarded there instead as its own request: POST, Content-Type: application/json, body { command, value }.

  • command — the matching entry from this agent's own config, unchanged: name, equipment, driver, and interlock if one's set.
  • value — null for a discrete command, since its value is already fixed in command.driver.value. For an analogical command it's the setpoint supplied at runtime, since the config carries no value for those (see Agent configuration).

A discrete command, configured with a fixed value:

command
{
  "name": "open",
  "equipment": "brk_10",
  "driver": { "type": "discrete", "value": 1, "path": "1" }
}
POST webhookjson
{
  "command": {
    "name": "open",
    "equipment": "brk_10",
    "driver": { "type": "discrete", "value": 1, "path": "1" }
  },
  "value": null
}

An analogical command — no value in the config, the setpoint travels in the webhook body instead:

command
{
  "name": "setpoint",
  "equipment": "brk_10",
  "driver": { "type": "analogical", "path": "2" }
}
POST webhookjson
{
  "command": {
    "name": "setpoint",
    "equipment": "brk_10",
    "driver": { "type": "analogical", "path": "2" }
  },
  "value": 42.5
}

Any non-2xx response is treated as a failed command. Either way, the outcome is recorded against the request and queryable over GraphQL (requestUpdate), same as a command sent to any other protocol agent.

02
Docker image

Image: khorde/rest-agent:latest. 9090 is the one port above — /addr, /batch, and /health all live on it — same compose shape as every agent (see Agent configuration). Save the service account key from Connect a REST agent next to it, renamed to service-user.json. Its own config.yaml:

config.yaml
rest:
  host: 0.0.0.0
  port: 9090
  # Uncomment to forward commands received from SCADA to your own equipment:
  # webhook: "http://host.docker.internal:8081"
agent:
  broker:
    ip: host.docker.internal
    port: "4222"
    tls: false
  credentials:
    url: http://auth.localhost:9310
    service_account_path: service-user.json
  command_timeout: 10s
Next

Agent configuration

The full schema shared by every protocol. Agent configuration.

Walk through it live

Create an agent, upload a config, and watch it over GraphQL. Connect a REST agent.

Other protocols

IEC 60870-5-104 (client), (server), and IEC 61850 agents work the same way.

Taking this past your laptop?

Talk to us