Three things a paired wall panel needed.
The scope check now walks the panel's widgets instead of allowing the
`/messages/` prefix wholesale: a screen may publish what its own controls and
querying charts point at, read the history of what its tiles draw, and nothing
else — the catalogue of every message in the installation included. The same
walk that already bounds its socket, so both surfaces agree.
Pending pairing codes moved out of the per-process dictionary into Redis, keyed
per code with the code's own TTL and indexed in a zset so the fifty-code cap
means the same thing to every worker. Without a Redis there is one process by
definition, and the dictionary stays.
And a per-panel nonce in the token, bumped by `POST /panels/{id}/unpair`: that
refuses the screen hanging there without touching the panel, its dashboards or
their arrangement. A save cannot write the nonce back, so a stale client cannot
undo a revocation. Only for a credential this installation signed — one the
portal minted carries no nonce and is revoked at the hub.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tULRZJUkZsw7rMJ3h4xvu
225 lines
9.1 KiB
Markdown
225 lines
9.1 KiB
Markdown
# The HTTP API
|
|
|
|
Everything the browser does, the API does first. The dashboard is a generated
|
|
client of this schema, not a privileged path into the engine — so anything you
|
|
can click, you can script.
|
|
|
|
Base URL: `https://api.${DOMAIN}/api/v1`, or `http://127.0.0.1:8000/api/v1` for
|
|
a `fluksio serve` installation.
|
|
|
|
```sh
|
|
export FLUKSIO=http://127.0.0.1:8000/api/v1
|
|
```
|
|
|
|
## Authenticating
|
|
|
|
```sh
|
|
export TOKEN=$(curl -s -X POST $FLUKSIO/login/access-token \
|
|
-d "username=admin@example.com&password=..." | jq -r .access_token)
|
|
|
|
curl -s $FLUKSIO/users/me -H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
A bearer token, valid for eight days. `POST /login/test-token` checks one.
|
|
Password recovery and reset are `POST /password-recovery/{email}` and
|
|
`POST /reset-password/`.
|
|
|
|
Agents authenticate differently — see [Agents over MCP](agents.md).
|
|
|
|
!!! tip "The interactive schema"
|
|
|
|
When `ENVIRONMENT` is not `production`, the full OpenAPI schema is at
|
|
`/docs` (Swagger) and `/redoc`, and the raw document at
|
|
`/api/v1/openapi.json`. That is the authoritative reference; this page is
|
|
the tour.
|
|
|
|
It is closed in production on purpose: the schema enumerates every endpoint
|
|
the installation serves, including the paths webhook nodes mounted at
|
|
runtime.
|
|
|
|
## Flows
|
|
|
|
| Method | Path | What |
|
|
|---|---|---|
|
|
| `GET` | `/flows/` | every flow, with node counts, draft and running state |
|
|
| `GET` | `/flows/{name}` | one flow — the draft if there is one — with node status and issues |
|
|
| `PUT` | `/flows/{name}` | save a draft (`version` must match, or 409) |
|
|
| `POST` | `/flows/{name}/publish` | put the draft live |
|
|
| `POST` | `/flows/{name}/discard-draft` | throw the draft away |
|
|
| `POST` | `/flows/{name}/rename` | rename it |
|
|
| `DELETE` | `/flows/{name}` | delete it |
|
|
| `GET` | `/flows/node-types` | every node type and its parameter schema |
|
|
| `GET` | `/flows/graph` | every flow as one graph — what Home draws |
|
|
|
|
Reading a flow returns the *draft* when one exists, along with a preview of how
|
|
it would run: node statuses and validation issues for the version you are
|
|
editing, not the one running underneath it.
|
|
|
|
### Node source
|
|
|
|
```sh
|
|
curl -s $FLUKSIO/flows/house/nodes/decide/source -H "Authorization: Bearer $TOKEN"
|
|
curl -X PUT $FLUKSIO/flows/house/nodes/decide/source -H "Authorization: Bearer $TOKEN" \
|
|
-H 'Content-Type: application/json' -d '{"code": "def process(x):\n return {\"y\": x * 2}\n"}'
|
|
```
|
|
|
|
`POST .../share` promotes a node's source to the shared library;
|
|
`POST .../unshare` gives it a private copy back. `GET /flows/library` lists the
|
|
shared sources and which flows use each.
|
|
|
|
### Running and controlling
|
|
|
|
| Method | Path | What |
|
|
|---|---|---|
|
|
| `POST` | `/flows/{name}/start` · `/stop` | activate or tear down its subscriptions and schedules |
|
|
| `POST` | `/flows/{name}/pause` · `/resume` | hold messages instead of running them |
|
|
| `POST` | `/flows/{name}/step` | release exactly one held message |
|
|
| `POST` | `/flows/{name}/validate` | the issues, without saving |
|
|
| `POST` | `/flows/{name}/run` | run every node once, from the values you pass |
|
|
| `POST` | `/flows/{name}/nodes/{id}/trigger` | feed values into one node |
|
|
| `POST` | `/flows/{name}/nodes/{id}/cancel` | kill the worker running it right now |
|
|
| `POST` | `/flows/{name}/nodes/{id}/acknowledge` | clear the failure the canvas is marking |
|
|
|
|
`POST /flows/{name}/run` on a **batch** flow submits a run instead, because
|
|
that is what running one means — the parameters, the series and the result are
|
|
the point, and a call that quietly did something else would be a trap.
|
|
|
|
## Messages
|
|
|
|
```sh
|
|
curl -s $FLUKSIO/messages/ -H "Authorization: Bearer $TOKEN"
|
|
curl -X POST $FLUKSIO/messages/house.setpoint -H "Authorization: Bearer $TOKEN" \
|
|
-H 'Content-Type: application/json' -d '{"value": 22.5}'
|
|
curl -s $FLUKSIO/messages/house.temperature/history -H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
`GET /messages/` is the catalogue: every message any published flow declares,
|
|
with its last value. Publishing puts a value into the graph exactly as a
|
|
dashboard control does — which means only a message some flow *declares* can be
|
|
published to. Flows own the namespace; everything else is a client of it.
|
|
|
|
## Runs
|
|
|
|
| Method | Path | What |
|
|
|---|---|---|
|
|
| `POST` | `/runs/flows/{name}` | queue one run — `{"params": {...}, "seed": 7, "draft": false}` |
|
|
| `POST` | `/runs/flows/{name}/sweep` | queue many, sharing a `group_id` |
|
|
| `GET` | `/runs` | the queryable history: `?flow=`, `?status=`, `?group=`, `?digest=`, `?limit=` |
|
|
| `GET` | `/runs/{id}` | one run in full: params, result, per-node record, artifacts |
|
|
| `POST` | `/runs/{id}/cancel` | stop it |
|
|
| `GET` | `/runs/{id}/metrics?name=&stride=` | one metric's series, in step order |
|
|
| `GET` | `/runs/series/compare?ids=a,b,c&metric=` | that metric across several runs |
|
|
|
|
Submitting answers immediately with a `queued` run. Wrong parameters — an
|
|
undeclared name, a value of the wrong type — come back as a 422 naming the
|
|
problem, before anything executes.
|
|
|
|
`?digest=` filters by the hash of the parameters, which is how you find "every
|
|
run that used exactly this configuration".
|
|
|
|
`compare` answers in the same shape a chart widget draws, so three training
|
|
curves side by side is a widget binding rather than a screen of its own.
|
|
|
|
See [Runs: pipelines that finish](../concepts/runs.md).
|
|
|
|
## Artifacts
|
|
|
|
```sh
|
|
curl -X PUT $FLUKSIO/artifacts -H "Authorization: Bearer $TOKEN" \
|
|
--data-binary @model.pt
|
|
curl -s $FLUKSIO/artifacts/sha256:abc... -H "Authorization: Bearer $TOKEN" -o model.pt
|
|
```
|
|
|
|
Content-addressed, so uploading the same bytes twice stores them once. Node
|
|
code normally reaches these through `fluksio.save_artifact` /
|
|
`fluksio.load_artifact` rather than here.
|
|
|
|
## Dashboards and panels
|
|
|
|
| Method | Path | What |
|
|
|---|---|---|
|
|
| `GET` | `/dashboards/` | every dashboard, without its contents |
|
|
| `GET` | `/dashboards/{name}?draft=true` | the published document, or the editor's copy |
|
|
| `POST` | `/dashboards/{name}` | create one |
|
|
| `PUT` | `/dashboards/{name}` | save a draft |
|
|
| `POST` | `/dashboards/{name}/publish` · `/discard` · `/rename` | |
|
|
| `GET` `PUT` | `/panels/` | which device shows which dashboards |
|
|
| `POST` | `/panels/pair` | start a pairing |
|
|
| `GET` | `/panels/pair/{code}` | what is holding a code |
|
|
| `POST` | `/panels/{id}/unpair` | drop this panel's credential, keep the panel |
|
|
|
|
## Secrets, modules, alerts
|
|
|
|
```sh
|
|
curl -s $FLUKSIO/secrets/ -H "Authorization: Bearer $TOKEN" # names only
|
|
curl -X PUT $FLUKSIO/secrets/influx-token -H "Authorization: Bearer $TOKEN" \
|
|
-H 'Content-Type: application/json' -d '{"value": "..."}'
|
|
|
|
curl -s $FLUKSIO/modules/ -H "Authorization: Bearer $TOKEN"
|
|
curl -X POST $FLUKSIO/modules/apply -H "Authorization: Bearer $TOKEN" \
|
|
-H 'Content-Type: application/json' -d '{"requirements": "numpy>=2\n"}'
|
|
|
|
curl -s $FLUKSIO/alerts/config -H "Authorization: Bearer $TOKEN"
|
|
curl -X POST $FLUKSIO/alerts/test/my-phone -H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
Secrets are write-only over the API: you can list names and set values, never
|
|
read one back.
|
|
|
|
## Observability
|
|
|
|
| Path | What |
|
|
|---|---|
|
|
| `/observability/summary` | engine health — always 200, degraded or not |
|
|
| `/observability/timeseries` | executions and failures over a window |
|
|
| `/observability/flows` | per-flow rollups with a 60-slice trend |
|
|
| `/observability/runs` | recent cascades, with `?flow=`, `?since=`, `?until=` |
|
|
| `/observability/events?kind=failure\|audit` | what went wrong, or who changed what |
|
|
| `/observability/dead-letter` | work the engine gave up on |
|
|
|
|
`GET /utils/health/` is the deep health check the container probe uses: it
|
|
fails when the event loop is wedged or the state backend is gone, not just when
|
|
the process is dead.
|
|
|
|
## Workers
|
|
|
|
| Method | Path | What |
|
|
|---|---|---|
|
|
| `GET` | `/workers` | what is attached, its labels and how busy it is |
|
|
| `POST` | `/workers/tokens` | mint a worker credential (superuser; shown once) |
|
|
| `GET` | `/workers/runtime` | the node runner's source, for a host without pip |
|
|
| `WS` | `/workers/attach` | where a worker dials in |
|
|
|
|
See [Remote workers](workers.md).
|
|
|
|
## Live events
|
|
|
|
```text
|
|
ws://127.0.0.1:8000/api/v1/flows/ws?token=<access token>
|
|
```
|
|
|
|
The websocket authenticates from its query string. It sends a snapshot on
|
|
connect and then every engine event: node executions, values published, health
|
|
changes, run started and finished. This is what the canvas and the dashboards
|
|
draw from.
|
|
|
|
## Errors
|
|
|
|
| Code | Means |
|
|
|---|---|
|
|
| `400` | the request was malformed, or the node refused it with a message |
|
|
| `401` / `403` | not signed in, or not allowed |
|
|
| `404` | no such flow, dashboard, run or message |
|
|
| `409` | someone else saved first — the body carries `current_version` |
|
|
| `422` | a parameter, port or binding did not typecheck |
|
|
| `503` | that subsystem is not available on this installation |
|
|
|
|
A 409 on a save or a publish is not an error to retry blindly: it means the
|
|
stored version moved past the one you were editing. Re-read, merge, save again.
|
|
|
|
## Generating a client
|
|
|
|
The frontend's TypeScript client is generated from the OpenAPI schema
|
|
(`make generate-client`). Any OpenAPI generator will do the same for your
|
|
language — point it at `/api/v1/openapi.json` on a non-production installation.
|