Skip to content

API Overview

The backend exposes two REST surfaces on port 5000, plus a gRPC service and a SignalR hub:

SurfaceBase pathAuthAudience
Internal API/api/…JWT bearer (login session)The dashboard UI; usable for on-box scripting
External API/api/external/v1/…X-AiBoard-ApiKey headerThird-party integrations (SCADA, historians)
gRPC Inferenceport 50051none (internal network only)Backend ↔ inference runtime
SignalR hub/hub/realtimeJWT (?access_token=)Live dashboard updates

Every internal endpoint requires authentication by default (deny-by-default policy); only POST /api/auth/login and GET /api/system/health are anonymous. Two roles exist: admin (full control) and viewer (read-only dashboards). Interactive API docs (Swagger UI) are served at http://<box>:5000/.

POST /api/auth/login

Exchange username/password for a JWT (8-hour lifetime). Failed logins are rate-limited per IP (5 per 60 s).

Authorization: Bearer <jwt>

There are no refresh tokens — re-login when the token expires. GET /api/auth/me returns the identity behind a token. The admin account is created at install time by the bundle installer (seed-admin); there are no default credentials.

Input (read path) and output (write path) datasources are managed separately under /api/datasources/input and /api/datasources/output — both admin-only. Each supports the same lifecycle:

Verb + path (relative)Purpose
GET / · GET /{id}List / detail (secret fields redacted as ***)
POST / · PUT /{id} · DELETE /{id}Create / update / delete
GET /plugins · GET /plugins/{type}/schemaAvailable protocol plugins + their config form schema
POST /test-connection · POST /{id}/test-connectionProbe reachability
POST /{id}/tags · POST /{id}/browse-tagsReplace tag mappings / ask the device for its tag list

Datasources are pure connection management: what exists and how to reach it. Which model runs on which input, and which pipeline is live, belong to flows — see the table below. Output datasources additionally support POST /{id}/test-write — see Output Datasources.

Base path /api/flows. A flow binds one input datasource, one model version and any number of output datasources. It is the pairing, and enabling it is what arms the pipeline.

Verb + path (relative)Purpose
GET / · GET /{id}List / detail
POST / · PUT /{id} · DELETE /{id}Create / update / delete
POST /{id}/enableArm this flow to Ready (body { "enabled": true | false })

At most one flow may be enabled at a time; enabling one stands the previous one down. Editing an enabled flow returns 409 disable_flow_first — a live pipeline is not re-pointed underneath itself.

Enabling arms the flow to Ready; it does not start streaming. Starting is still POST /api/inference/start, so “which flow is selected” and “is it streaming” stay separate facts.

GET /api/models

List all model versions (any authenticated user).

POST /api/models/upload

Upload an .onnx file (admin). Validated via the inference runtime; versions are immutable.

POST /api/models/{modelId}/activate/{version}

Activate a version (admin).

POST /api/models/{modelId}/rollback

Re-activate the previous valid version (admin).

Also: GET /{modelId}/active, GET /{modelId}/history, DELETE /{modelId}/{version}, and DELETE /{modelId}/cleanup (prune old versions, keep-count configurable).

GET /api/inference/status

Current state: idle / ready / running, active datasource, loaded model.

POST /api/inference/start

Begin streaming (admin). 409 if the datasource is not Ready.

POST /api/inference/stop

Stop streaming gracefully — buffered predictions drain to output sinks first (admin).

GET /api/inference/stats

Latency aggregation feeding the Inference Stats page.

GET /api/inference/backpressure

Hot-path counters: drops, sink blocking, channel depth. Monotonic since startup.

Also: GET /api/inference/predictions/recent, GET /api/inference/payloads/{requestId}, and per-model latency alert thresholds under /api/inference/thresholds (PUT/DELETE admin).

EndpointPurpose
GET /api/system/health (anonymous)Liveness — used by the Docker healthcheck
GET /api/system/status · GET /api/system/metricsRuntime status; CPU/GPU/memory metrics
GET /api/logsPaginated centralized logs (backend + inference)
GET/PUT /api/dashboard/layoutPer-user dashboard layout
GET/PUT/DELETE /api/me/preferencesPer-user preference blob
GET /api/admin/inference-config/export

Export the whole pipeline — datasources, tag mappings and flows — as one versioned JSON envelope (secrets redacted).

POST /api/admin/inference-config/import

Import an envelope transactionally — any item failure rolls back the whole file. Modes: merge (default) or replace.

Designed for third-party systems. Disabled auth-wise until an API key exists; keys are issued on the box CLI (issue-api-key), shown once, and revocable (list-api-keys, revoke-api-key). Requests are rate-limited (100 per 60 s per client).

X-AiBoard-ApiKey: ak_<your-key>
GET /api/external/v1/predictions/latest

Most recent prediction: output values, confidence, model version, window timestamps.

GET /api/external/v1/predictions/history?limit=&offset=

Recent predictions (in-memory, ~1 hour retention, limit ≤ 1000). 503 while inference is down.

Validation failures return HTTP 400 with machine-readable codes (for example name_already_exists, shape_mismatch, model_not_paired, config_invalid:port:range). Lifecycle conflicts return 409 (not_ready, version_exists). The dashboard maps these codes to localized messages.