Other routes
The remaining routes: the two webhook integrations (event streams for tag changes, alarm pipelines for alarms), the list of live /sync clients, and the cron module's jobs and runs. Event streams, pipelines and clients are admin only because they call out of the gateway or expose who is connected.
Event streams
Batches of tag changes posted to a webhook. Dashboard side: Event streams.
| Method and path | Role | Purpose |
|---|---|---|
GET /api/v1/admin/event-streams | admin | Every stream, by name |
POST /api/v1/admin/event-streams | admin | Create (at most 20 streams) |
PUT /api/v1/admin/event-streams/{id} | admin | Replace |
DELETE /api/v1/admin/event-streams/{id} | admin | Delete (204) |
POST /api/v1/admin/event-streams/{id}/test | admin | Send one made-up change now |
GET /api/v1/admin/event-streams/deliveries?limit=100 | admin | Recent deliveries, newest first, kept in memory |
StreamBody:
| Field | Type | Required | Meaning |
|---|---|---|---|
name | string | yes | Up to 80 characters |
enabled | boolean | no | Default true |
tagPaths | string[] | yes | 1 to 50 paths, each up to 300 characters |
bufferSeconds | integer | no | 1 to 300, default 5: how long changes are collected before a post |
maxBatch | integer | no | 1 to 1000, default 100: a batch is posted when it reaches this size |
webhookUrl | string | yes | Full http or https URL, up to 500 characters |
The test route posts [{ "tagPath": "Test.Tag", "value": 1.0, "quality": "Good", "timestamp": "<ISO-8601>" }] and answers { "status", "detail" }. Deliveries are { "at", "streamId", "streamName", "events", "status", "detail" }.
Alarm pipelines
Who gets told about an alarm: a webhook called on an alarm transition. Dashboard side: Alarm pipelines.
| Method and path | Role | Purpose |
|---|---|---|
GET /api/v1/admin/alarm-pipelines | admin | Every pipeline, by name |
POST /api/v1/admin/alarm-pipelines | admin | Create |
PUT /api/v1/admin/alarm-pipelines/{id} | admin | Replace |
DELETE /api/v1/admin/alarm-pipelines/{id} | admin | Delete (204) |
POST /api/v1/admin/alarm-pipelines/{id}/test | admin | Send a made-up alarm now |
GET /api/v1/admin/alarm-pipelines/deliveries?limit=100 | admin | Deliveries, newest first, limit 1 to 500 |
PipelineBody:
| Field | Type | Required | Meaning |
|---|---|---|---|
name | string | yes | Up to 80 characters |
enabled | boolean | no | Default true |
trigger | string | yes | active, acknowledged or cleared |
minSeverity | integer | no | 0 to 1000, default 0 |
delaySeconds | integer | no | 0 to 3600, default 0: wait this long, and do not send if the alarm left the state meanwhile |
webhookUrl | string | yes | Full http or https URL, up to 500 characters |
The payload is the alarm object described in Alarms. The test route sends { "id": "test", "name": "Test alarm", "tagPath": "Test.Tag", "severity": 500, "state": "active", "value": 1.0 } and answers { "status", "detail" }. Deliveries are stored in the database: { "id", "at", "pipelineId", "pipelineName", "alarmName", "tagPath", "event", "status", "detail" }.
Clients
The open /sync connections. Dashboard side: Clients.
| Method and path | Role | Purpose |
|---|---|---|
GET /api/v1/admin/clients | admin | Every open socket with who, where from and what it costs |
GET /api/v1/admin/clients/{id}/subscriptions | admin | The tags one socket subscribes to |
{ "at": "…", "clients": [ {
"id": "…", "principalId": "…", "authKind": "session", "name": "…", "email": "…", "role": "operator",
"remoteAddress": "10.0.0.5", "userAgent": "…", "origin": "https://app.scadex.io", "host": "app.scadex.io", "connectedAt": "…",
"subscriptions": 42, "messagesIn": 120, "messagesOut": 8800, "bytesIn": 9000, "bytesOut": 1200000,
"writes": 3, "writesRefused": 0, "dropped": 0, "queuedChars": 0, "alarms": true, "replay": null, "lastIn": "…", "lastOut": "…" } ] }
authKind is session for a browser signed in with a cookie or apiKey for a key; name and role then come from the user or the key. remoteAddress honors X-Real-Ip and X-Forwarded-For behind a proxy. Subscriptions: { "at", "subscriptions": [{ "path", "since", "updates", "lastUpdate" }] }. A closed connection is 404. The same numbers are published as @gateway.clients tags.
Cron module
Under /api/v1/modules/io.scadex.cron. Viewers can read; creating, changing, deleting, running and testing a job need engineer. While the module is not running the routes answer 503. Background in Cron and Cron scripts.
| Method and path | Role | Purpose |
|---|---|---|
GET /api/v1/modules/io.scadex.cron/status | viewer | Jobs, how many are failing or running, the next run, the last 24 hours |
GET /api/v1/modules/io.scadex.cron/jobs | viewer | The jobs with health, next run, latest runs and a day's counts |
POST /api/v1/modules/io.scadex.cron/jobs | engineer | Create (201) |
GET /api/v1/modules/io.scadex.cron/jobs/{id} | viewer | One job |
PUT /api/v1/modules/io.scadex.cron/jobs/{id} | engineer | Replace; also pauses and resumes through enabled |
DELETE /api/v1/modules/io.scadex.cron/jobs/{id} | engineer | Delete |
POST /api/v1/modules/io.scadex.cron/jobs/{id}/run | engineer | Run now, paused or not; answers when it has finished |
POST /api/v1/modules/io.scadex.cron/test | engineer | Try a job's action without keeping a record; a script's writes are reported, not made |
GET /api/v1/modules/io.scadex.cron/runs?job=&outcome=&before=&limit=50 | viewer | Runs, newest first; limit 1 to 200; pass nextBefore as before |
GET /api/v1/modules/io.scadex.cron/runs/{id} | viewer | One run with its log, value and writes |
GET /api/v1/modules/io.scadex.cron/preview?schedule=&timeZone=&count= | viewer | Check a schedule and list its next times |
CronJobInput, used by POST, PUT and test:
| Field | Type | Required | Meaning |
|---|---|---|---|
name | string | yes on create | |
description | string | no | |
schedule | string | yes on create | Five-field cron expression (minute, hour, day of month, month, day of week) |
timeZone | string | yes on create | IANA time zone; daylight saving handled as Unix cron does |
enabled | boolean | no | false pauses the job |
action | object | yes on create | { "kind": "script", "script": "…" } or { "kind": "write", "path": "Plant.Counter", "value": 0 } |
catchUp | boolean | no | After downtime, run once for the missed times |
failureTag | string | no | A boolean tag set true while the last run failed, false once one succeeds |
A job in responses carries id, the fields above, createdAt, updatedAt, updatedBy, activeSince, plus its schedule error if any, nextRun, whether it is running, its latest runs and a day's counts (runs, succeeded, failed, skipped, missed, averageMs). A duplicate name is 409; a bad schedule or time zone is 400.
A run records when it was due, why it ran (on schedule, by hand, or catching up), how long it took, its log lines ({level, message}), its returned value, its writes ({path, value, applied, error}) and the outcome: succeeded, failed, skipped (the previous run was still going; runs never queue) or missed (the gateway was down or the scheduler fell behind; one record covers a stretch). Runs are kept for 90 days, at most 2000 per job. Scheduled writes are audited as cron:<job name>, manual runs as the person who asked, both with correlation id cron-run-<id>.