Skip to content

REST API

The JSON-over-HTTP API the canvas UI uses: health, sources, the flow document, devices, config, observability and live WebSocket streams. Bearer-token protected.

Updated View as Markdown

The same API the canvas UI uses, served on bind_addr:health_check_port (default 127.0.0.1:3000).

Auth. Every route except GET /api/health, GET /api/ready and the login endpoints requires a bearer token (Authorization: Bearer <token>: the legacy api_token, an admin, or a named opx_... token) or an SSO session cookie (non-GET also needs X-Opex-CSRF). Each route has a minimum role (viewer < operator < editor < admin); a lower role gets 403 {"error", "required_role", "role"}. WebSockets accept ?token=<token>. Every response carries X-Request-Id. Unknown /api/* paths return 404 {"error":"not found"}; failures use real 4xx/5xx status codes. See Security.

Method & path Description
GET /api/health Liveness (public).
GET /api/ready Readiness (public): 200 {"ready":true} or 503. With ha: it adds the role: 200 {"ready":true,"role":"active"} on the serving node, 503 {"ready":false,"role":"standby"} on a standby (use it as the load-balancer check; /api/health stays 200).
GET /api/status, /api/health/report Connector + adapter status (includes an ha object: role, node, leader, takeovers; {"enabled":false} without HA; an opcua_server object (endpoint, sessions, devices; {"enabled":false} when off), per-sink sinks[]: published / dropped / connected / last_error / backlog, and engine: flow version, loss counter and executor stats such as unrouted, queue_depth, node_latency); edge health snapshot.
GET /api/devices, /api/devices/{id} Known devices + status.
GET /api/history, /api/history/devices Retained records (device_id, from, to, limit).
GET /api/sources, POST /api/sources, DELETE /api/sources/{key} Sources + live status; add/remove at runtime (persisted to sources.runtime.json).
POST /api/sources/{key}/inject Fire an inject source.
POST /api/ingest/{source}/{id}?wait_ms= Push a JSON object into the flow source matching {source}:{id} or {source}:* (never *) and wait for the outcome: 200 done, 422 failed, 503 retry, 202 pending, with error and the printer jobs the record caused. See Coding printers.
POST /api/hooks/{name} Signed webhook ingest into the flow source webhook:{name}. No bearer token: authenticated by the hook’s HMAC signature (doku or hmac_sha256); 401 bad signature, 404 unknown hook, 413 too large, then 200/202/422/503 as for ingest (on_receipt answers 200 {"result":"accepted"}). The record is the JSON body plus _hook. Counters in GET /api/status → engine.webhooks[]. See Signed webhooks.
GET /api/printers, GET /api/printers/lines, GET/PUT/DELETE /api/printers/{id} Coding printers (config incl. line, connection, job counters); printers grouped by production line { lines: [{ line, printers }] }; add/replace/remove (persisted to printers.runtime.json).
POST /api/printers/import[?dry_run=true] Bulk create/replace from a YAML printers: list (the config / deploy/*/printers.yaml shape), a bare list, or JSON (Content-Type: application/json). Everything is validated first and applied atomically (200 { ok, create[], update[], errors[] }), or nothing is (422, same body). dry_run=true only reports { create, update, errors }.
POST /api/printers/{id}/status, POST /api/printers/{id}/jobs Live status exchange with a printer; run a job by hand.
GET /api/printers/jobs?printer=&invocation=&before=&limit= Printer job log, newest first.
GET /api/flow The flow document (the canvas; the single source of truth for routing): { version, flow: { flows, nodes, edges }, seeded, warnings }. flows is a list of named canvases { id, name, disabled? } (default one main); every node has a flow id (default: the first flow). Flows only group nodes: wires never cross flows, match stays unique across all of them, and a disabled flow behaves as if all its nodes were disabled. seeded is true until the first deploy (the document was built from the config’s transform section and legacy state). warnings are the issues that need no compile (e.g. an unconnected node, a sink that is not configured on this connector).
PUT /api/flow Deploy { flow, if_version }: validates and compiles every source, persists <data_dir>/flow.json atomically, then swaps all pipelines in one step. 200 { version, warnings }; 409 { error, version } when if_version is stale; 422 { errors, warnings } (each issue { node_id?, edge_id?, message }) and the running flow is untouched. Deploys are serialised.
POST /api/flow/validate { flow } → { errors, warnings } without deploying.
POST /api/flow/test Dry run of one source: { flow, source_node, record? } → { ok, record_used, steps[], sink_effects[] } (per-node input / output / error / duration_us; no sink or HTTP side effects). Without record, the last real record seen for the source’s match is used (404 if none yet).
GET /api/flow/last-record?match= Last real record seen for a key matching match (*, {source}:*, {source}:{machine}): { key, record, ts }, or 404.
POST /api/script/validate, POST /api/script/generate, GET /api/script/ai-status Syntax-check a transform script ({ backend, script } → { valid, error? }); AI-generate or edit one ({ instruction, current?, history?, sample_record?, match?, target? }, validated + dry-run; see AI generator); AI setup status { configured, missing?, model?, base_url? }.
GET /api/pipeline/trace/{id}, /api/pipeline/traces Sampled execution traces.
GET /api/pipeline/dead-letters, GET|PUT /api/pipeline/dead-letters/{id}, POST /api/pipeline/dead-letters/{id}/replay, POST /api/pipeline/dead-letters/{id}/discard, POST /api/pipeline/dead-letters/replay, POST /api/pipeline/dead-letters/discard, GET /api/pipeline/dead-letters/audit The pipeline dead-letter queue: list (status, source, node, q, since, until), inspect, correct ({value?, origin?}), replay into the source or a node ({to, node, wait_ms}), discard, bulk by filter, and the audit trail (the actor is the authenticated identity). Writes need operator. See Dead letters.
GET /api/reconcile/reports, GET /api/reconcile/reports/{id}, GET /api/reconcile/reports/{id}/csv, GET /api/reconcile/ledger, GET /api/reconcile/ledger/entries Reconciliation reports of reconcile nodes (filter name, day, ok), one report with its exceptions, the CSV export, and the hub-side ledger per ledger / side / day. See Reconciliation reports.
GET /api/cases, /api/cases/summary, /api/cases/csv, GET /api/cases/{id}, POST /api/cases/{id}/assign|comment|status|link, POST /api/cases/bulk, POST /api/cases/from-report/{id}, GET|POST /api/cases/digest Exceptions workbench: every reconcile exception is a case (open, investigating, resolved, ignored) with assignee, comments, links, ageing, CSV and a daily digest; operators work them, every change is audited. See Finance controls.
GET /api/approvals, GET /api/approvals/{id}, POST /api/approvals/{id}/approve|reject|resume Records parked by approve nodes: the inbox, decide (the node’s role / users, a rejection needs a comment), resume an interrupted one. See Finance controls.
GET /api/posting, GET|POST /api/golive/requests, POST /api/golive/requests/{id}/approve|reject|cancel Go-live gate: posting modes per node with their sign-off; an editor requests, a second designated approver approves switching a ${var:} posting mode to live in a protected environment (PUT /api/vars answers 409 go_live_required). See Finance controls.
GET /api/openapi, PUT /api/openapi/{name} Vendored OpenAPI specs for http nodes.
GET /api/discovery, /api/discovery/pi; GET/POST /api/mapping, POST /api/mapping/csv Tag discovery + mapping table.
GET /api/backfill Backfill replay progress.
GET /api/push/status, GET/DELETE /api/push/dead, POST /api/push/dead/replay Push queue health; inspect / purge / replay permanently failed pushes.
GET /api/config Running config with secrets redacted (***, including the token in push_endpoint).
POST /api/config/reload Re-read the config file; applies push settings and poll interval (adapters need a restart).
GET /api/license/status License state: { enabled, state: "valid"|"offline_grace"|"invalid"|"unlicensed"|"disabled", plan, expires_at, offline_valid_until, activation_id_short, device_id_short, key_last4, key_source: "config"|"ui"|null, last_check_at, reason?, error? } (Unix seconds; no secrets, the key shows only its last 4 characters).
POST /api/license/activate { key }, POST /api/license/revalidate, POST /api/license/deactivate Enter or replace the key (stored in license.json), check now, free this device’s seat. 200 returns the new status; failures are { ok: false, error, reason }: 400 bad input, 409 not allowed here (licensing disabled, key set in the config file, not activated), 422 the worker refused (invalid, revoked, suspended, expired, seats_exhausted, deactivated), 502 worker unreachable (network). See Licensing.
GET /metrics, GET /api/obs/{traces,series,alerts} Observability. Requires a build with the telemetry feature.
POST /api/obs/test Send a test alert to every configured channel (telemetry.alerts: webhook, Telegram, email, Teams, WhatsApp). Every build. Returns {ok, results, channels:[{channel, ok, detail}]}. See Alerts.
GET /api/schedules, POST /api/schedules/preview Deployed schedule:{id} sources with next runs and last tick outcome; preview the next fire times of {cron, timezone?, count?} (422 {ok:false, error} when invalid). See Schedule source.
GET /api/health/sla?range= Health dashboard data: runs, errors, retries, availability, p50/p95/p99 and sparkline series per flow and per external system, SLA state and open incidents. Every build. See SLA dashboard.
GET /api/reports/months, GET /api/reports/monthly?month=&format=json|html|csv&part=, POST /api/reports/monthly/send Monthly service report (HTML, CSV tables, JSON) and mailing it now. See Monthly service report.
GET /api/siem/status, POST /api/siem/test SIEM export: sinks and counters; one test event per sink. See SIEM export.
GET /api/openapi/published, GET /api/openapi/published.yaml OpenAPI 3.1 of every interface the connector exposes (webhooks with their signature schemes, ingest keys, app actions, mock services, management API). See Published OpenAPI.
GET /api/events, GET|PUT|DELETE /api/events/{name}, PUT /api/events, POST /api/events/{name}/validate, GET /api/events/asyncapi, GET /api/events/log The business-event catalogue (JSON Schema, owner, producers and consumers derived from the flow), its AsyncAPI 3.0 export and the event history. See Business events.
GET /api/lookups, PUT|DELETE /api/lookups/{name}, GET|POST /api/lookups/{name}/entries, POST /api/lookups/{name}/entries/delete, POST /api/lookups/{name}/import, GET /api/lookups/{name}/csv, GET /api/lookups/{name}/resolve Lookup tables (code lists, cross-references): entries, CSV import with dry run, CSV export, a single lookup. See Lookup tables.
GET /api/environment The instance’s environment {configured, name, color, protected} (badge; protected refuses direct deploys). See Environments.
WS /api/ws/collab, GET /api/collab/draft, POST /api/collab/deploy, POST /api/collab/discard The shared flow draft: realtime co-editing and presence socket (any role may watch, editor edits), the draft’s state and unsaved count, deploy the draft as a version with co-authors, discard it for everyone. See Editing together.
GET /api/versions, GET /api/versions/{n}, GET /api/versions/diff?from=&to=, POST /api/versions/{n}/rollback Version history of every deploy (actor, message, hash, provenance), node/edge/field diff, rollback = redeploy N as a new version. PUT /api/flow takes an optional message. See Version history.
GET /api/vars, PUT|DELETE /api/vars/{name} ${var:NAME} variables of this instance (editor reads, admin writes). See Variables.
GET /api/promotion, POST /api/promotions/send, POST /api/promotions, GET /api/promotions, GET /api/promotions/{id}, POST /api/promotions/{id}/approve|reject Signed promotion between environments: send a version to a target, receive a bundle (Ed25519, trusted sources), inbox with diff against live, approve (deploys as a new version with provenance) or reject. See Promotion.
GET /api/apps, GET|PUT|DELETE /api/apps/{id}, POST /api/apps/validate, POST /api/apps/{id}/publish|unpublish|revert, GET /api/apps/{slug}/runtime, POST /api/apps/{slug}/data/{source}, POST /api/apps/{slug}/actions/{action} Apps: JSON-defined web apps. Definitions and publishing need editor; the runtime endpoints check each source’s and action’s roles on the server. See Apps.
/mcp The MCP server for AI agents (streamable HTTP, same bearer token). Its tools call the same handlers as the endpoints above.
GET /api/auth/config (public), GET /api/auth/me, POST /api/auth/logout, GET /api/auth/oidc/login, GET /api/auth/oidc/callback (public) Sign-in: the login options ({oidc:{enabled, login_url, provider}, token_login}), the caller ({kind: user|token|legacy, name, email?, role, csrf?, session_expires_at?, mfa}), end a browser session, and the OIDC authorization-code + PKCE redirect / callback. See Security.
GET /api/auth/users, PUT /api/auth/users/{id}, GET|POST /api/auth/tokens, DELETE /api/auth/tokens/{id} admin: SSO users (role override {role_override, disabled}) and named API tokens (POST {name, role, expires_in_days?} → 201 {token, info}, the secret shown once).
GET /api/secrets, PUT|DELETE /api/secrets/{name} admin, audited: the local secrets behind ${secret:name}. GET returns names and change times only ({local:{writable, items}, vault:{configured}}); PUT {value} is write-only (409 without OPEX_MASTER_KEY). See Data protection.
GET /api/audit?actor=&action=&target=&result=&since=&until=&limit=&before=, GET /api/audit/csv admin: the append-only audit log (who, when, action, target, result, request id), newest first with next_before paging, and its CSV export. See Audit log.
WS /api/ws/live Live record stream.
WS /api/ws/events Live business events delivered to a hub sink (?type= filters, ?token= for browsers).
WS /api/ws/flow Flow telemetry, see below.
WS /api/ws/collab Shared draft and presence, see Editing together.

Flow WebSocket

GET /api/ws/flow?token= pushes JSON messages:

  • every second { "type": "stats", "ts", "nodes": { "<node id>": { "in", "out", "err", "rate", "avg_us", "last_ts", "last_error" } }, "unrouted", "sources": { "<match>": { "rate", "last_ts" } } } — counters are cumulative since start and aggregated per canvas node (a node shared by several sources counts once); rate is frames in per second over the last 5 s; unrouted counts records no source node matched.
  • { "type": "deployed", "version" } to every client after a successful deploy.
  • debug events, only after you subscribe: send { "debug": "all" }, { "debug": ["n2", "n7"] } or { "debug": "off" }; then { "type": "event", "ts", "node_id", "key", "phase": "in"|"out"|"drop"|"error", "payload", "error"? } (payloads over ~2 KB become { "_truncated": true, "preview": "…" }). At most 50 events/s per client; overflow is reported as { "type": "dropped", "count" } once a second. With nobody subscribed the engine builds no event payloads.
Navigation

Type to search…

↑↓ navigate↵ selectEsc close