docs
Docs / docs (push) Successful in 26s
Playwright Tests / test-playwright (1, 2) (push) Failing after 4m7s
Playwright Tests / test-playwright (2, 2) (push) Failing after 2m30s
pre-commit / pre-commit (push) Failing after 2m42s
Test Backend / test-backend (push) Failing after 3m3s
Compose Smoke Test / test-compose (push) Successful in 32s
Playwright Tests / merge-reports (push) Successful in 1m51s
Docs / docs (push) Successful in 26s
Playwright Tests / test-playwright (1, 2) (push) Failing after 4m7s
Playwright Tests / test-playwright (2, 2) (push) Failing after 2m30s
pre-commit / pre-commit (push) Failing after 2m42s
Test Backend / test-backend (push) Failing after 3m3s
Compose Smoke Test / test-compose (push) Successful in 32s
Playwright Tests / merge-reports (push) Successful in 1m51s
This commit is contained in:
+168
-201
@@ -1,274 +1,241 @@
|
||||
# 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.
|
||||
The API covers the same operations as the browser. Use it for scripts,
|
||||
integrations, or your own client.
|
||||
|
||||
Base URL: `https://api.${DOMAIN}/api/v1`, or `http://127.0.0.1:8000/api/v1` for
|
||||
a `fluksio serve` instance.
|
||||
Set the base URL for your instance:
|
||||
|
||||
```sh
|
||||
export FLUKSIO=http://127.0.0.1:8000/api/v1
|
||||
```
|
||||
|
||||
Use the port printed by `fluksio serve`. For Docker, use
|
||||
`http://api.localhost/api/v1`, `http://<host-ip>:8080/api/v1` on a LAN stack,
|
||||
or `https://api.<your-domain>/api/v1` for a deployment.
|
||||
All paths below are relative to this base.
|
||||
|
||||
## Authenticating
|
||||
|
||||
```sh
|
||||
export TOKEN=$(curl -s -X POST $FLUKSIO/login/access-token \
|
||||
-d "username=admin@example.com&password=..." | jq -r .access_token)
|
||||
`fluksio serve` signs the local CLI in automatically. To reuse its token
|
||||
from a project instance, with `jq` installed:
|
||||
|
||||
curl -s $FLUKSIO/users/me -H "Authorization: Bearer $TOKEN"
|
||||
```sh
|
||||
export TOKEN=$(jq -r .token .fluksio/client.json)
|
||||
```
|
||||
|
||||
A bearer token, valid for eight days. `POST /login/test-token` checks one.
|
||||
Password recovery and reset are `POST /password-recovery/{email}` and
|
||||
Adjust the path for `--global` or `--data-dir`. For a remote instance,
|
||||
use its login endpoint with the administrator credentials:
|
||||
|
||||
```sh
|
||||
export TOKEN=$(curl -s -X POST "$FLUKSIO/login/access-token" \
|
||||
--data-urlencode "username=admin@example.com" \
|
||||
--data-urlencode "password=<your-password>" | jq -r .access_token)
|
||||
|
||||
curl "$FLUKSIO/users/me" -H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
Session tokens last eight days by default. `POST /login/test-token` checks
|
||||
a token. Password recovery uses `POST /password-recovery/{email}` and
|
||||
`POST /reset-password/`.
|
||||
|
||||
Agents authenticate differently; see [Agents over MCP](agents.md).
|
||||
[Agents over MCP](agents.md) use separate OAuth tokens.
|
||||
|
||||
!!! tip "The interactive schema"
|
||||
!!! tip "Interactive API reference"
|
||||
|
||||
When `ENVIRONMENT` is not `production`, the full OpenAPI schema is at
|
||||
`/docs` (Swagger) and `/redoc`, and the raw document at
|
||||
`/api/v1/openapi.json`, for a browser on the engine's own machine (or any,
|
||||
with `API_DOCS_ENABLED=true`). That is the authoritative reference; this
|
||||
page is the tour.
|
||||
|
||||
It is closed in production: the schema enumerates every endpoint the
|
||||
instance serves, including paths webhook nodes mounted at runtime.
|
||||
Outside production, open `/docs` or `/redoc` on the API host.
|
||||
The schema is at `/api/v1/openapi.json`. Access is limited to loopback
|
||||
unless `API_DOCS_ENABLED=true`; the Docker development stack enables it.
|
||||
Production disables these endpoints.
|
||||
|
||||
## Flows
|
||||
|
||||
| Method | Path | What |
|
||||
| Method | Path | Action |
|
||||
|---|---|---|
|
||||
| `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. Its runs stay — a run is the record of what ran, and only `DELETE /runs` clears one. Refused with 409 while a run of it is `running` or `queued` |
|
||||
| `GET` | `/flows/node-types` | every node type and its parameter schema |
|
||||
| `GET` | `/flows/graph` | every flow as one graph — what Home draws |
|
||||
| `GET` | `/flows/` | list flows and their state |
|
||||
| `GET` | `/flows/{name}` | read the draft when present, with status and issues |
|
||||
| `PUT` | `/flows/{name}` | save a draft; send the current `version` |
|
||||
| `POST` | `/flows/{name}/publish` | publish; send `{"version": <current-version>}` |
|
||||
| `POST` | `/flows/{name}/discard-draft` | discard unpublished edits |
|
||||
| `POST` | `/flows/{name}/rename` | rename |
|
||||
| `DELETE` | `/flows/{name}` | delete; refused while a run is queued or running |
|
||||
| `GET` | `/flows/node-types` | list types and parameter schemas |
|
||||
| `GET` | `/flows/graph` | read the graph shown on Home |
|
||||
|
||||
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.
|
||||
Deleting a flow keeps its run history. Delete runs separately.
|
||||
|
||||
### 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"}'
|
||||
curl "$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"}'
|
||||
```
|
||||
|
||||
Writing a source is a superuser's, and so is any `PUT /flows/{name}` that
|
||||
adds a Function or Command node, retypes or repoints one, changes a Command
|
||||
node's settings, or changes any node's `resources.env`: each of them is code
|
||||
the engine runs. Anyone else gets a 403 and keeps the rest — wiring, titles,
|
||||
a Function node's settings and every other node.
|
||||
Writing code requires a superuser. So does adding, retyping, or repointing
|
||||
Function and Command nodes, changing Command settings, or changing
|
||||
`resources.env`. Other users can edit wiring, titles, and ordinary settings.
|
||||
|
||||
`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.
|
||||
Ordinary source edits stay in the draft until publishing. Shared library
|
||||
source changes affect its users immediately.
|
||||
`POST /flows/{name}/nodes/{id}/share` promotes a source to the library;
|
||||
`/unshare` makes it private again. `GET /flows/library` lists shared sources.
|
||||
|
||||
### Running and controlling
|
||||
|
||||
| Method | Path | What |
|
||||
| Method | Path | Action |
|
||||
|---|---|---|
|
||||
| `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}/start`, `/flows/{name}/stop` | activate or stop a live flow |
|
||||
| `POST` | `/flows/{name}/pause`, `/flows/{name}/resume` | hold or release incoming work |
|
||||
| `POST` | `/flows/{name}/step` | release one held message |
|
||||
| `POST` | `/flows/{name}/validate` | validate the current draft |
|
||||
| `POST` | `/flows/{name}/run` | run the current draft once with `{"inputs": {...}}` |
|
||||
| `POST` | `/flows/{name}/nodes/{id}/trigger` | feed a node with `{"values": {...}}` |
|
||||
| `POST` | `/flows/{name}/nodes/{id}/cancel` | stop active node code |
|
||||
| `POST` | `/flows/{name}/nodes/{id}/acknowledge` | clear its failure marker |
|
||||
|
||||
`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.
|
||||
A preview run can have real side effects. On a batch flow, `/run` submits a
|
||||
recorded run; use the run endpoints below for parameters and tracking.
|
||||
|
||||
## Messages
|
||||
|
||||
```sh
|
||||
curl -s $FLUKSIO/messages/ -H "Authorization: Bearer $TOKEN"
|
||||
curl -X POST $FLUKSIO/messages/house.setpoint -H "Authorization: Bearer $TOKEN" \
|
||||
curl "$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"
|
||||
curl "$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.
|
||||
The catalogue contains messages declared by published flows and their last
|
||||
values. You can publish only to declared messages, just as dashboard controls do.
|
||||
|
||||
## Runs
|
||||
|
||||
| Method | Path | What |
|
||||
| Method | Path | Action |
|
||||
|---|---|---|
|
||||
| `POST` | `/runs/flows/{name}` | queue one run — `{"params": {...}, "seed": 7, "draft": false, "no_cache": false}`. `"cause"` says where it came from — `api` (the default), `cli` or `sdk` |
|
||||
| `POST` | `/runs/flows/{name}/sweep` | queue many, sharing a `group_id` |
|
||||
| `POST` | `/runs/import` | record runs executed somewhere else, up to 200 per request. Answers `[{"external_id", "id", "created"}]` |
|
||||
| `GET` | `/runs` | the queryable history: `?flow=`, `?status=`, `?group=`, `?digest=`, `?since=`, `?before=`, `?limit=`, `?offset=` |
|
||||
| `DELETE` | `/runs?flow=` | every run of one flow, and everything hanging off them. `flow` is required. Refused with 409 while one of them is still going |
|
||||
| `GET` | `/runs/overview` | one row per flow that has runs, with how many are running or queued |
|
||||
| `GET` | `/runs/export/metrics?…&name=&stride=&format=` | every selected run's series as one long table: `run, name, step, ts, value` |
|
||||
| `GET` | `/runs/export/runs?…¶ms=&metrics=&format=` | one row per run: its inputs as columns, its final numbers, its status and provenance |
|
||||
| `GET` | `/runs/metrics/names?…` | every metric name the selected runs recorded, distinct; takes the export's own filters |
|
||||
| `GET` | `/runs/{id}` | one run in full: params, result, per-node record, artifacts |
|
||||
| `POST` | `/runs/{id}/cancel` | stop it |
|
||||
| `DELETE` | `/runs/{id}` | forget it, with its nodes, series and artifact rows. Cancel a live one first |
|
||||
| `POST` | `/runs/{id}/retry` | run the same thing again, as a new run naming this one |
|
||||
| `GET` | `/runs/{id}/metrics?name=&stride=` | one metric's series, in step order; every series of the run without `name` |
|
||||
| `GET` | `/runs/series/compare?ids=a,b,c&metric=&x=` | that metric across several runs. `x` is what to plot against: nothing or `step`, `time` (seconds since each run's own first reading), or another metric's name, joined on the step the two share |
|
||||
| `POST` | `/runs/flows/{name}` | queue a run with `{"params": {...}, "seed": 7}` |
|
||||
| `POST` | `/runs/flows/{name}/sweep` | queue runs with a shared group |
|
||||
| `POST` | `/runs/import` | import up to 200 completed runs |
|
||||
| `GET` | `/runs` | query history |
|
||||
| `GET` | `/runs/overview` | summarize runs per flow |
|
||||
| `GET` | `/runs/{id}` | read parameters, results, nodes, and artifacts |
|
||||
| `POST` | `/runs/{id}/cancel`, `/runs/{id}/retry` | cancel, or create a retry |
|
||||
| `DELETE` | `/runs/{id}` | delete a finished run and its records |
|
||||
| `DELETE` | `/runs?flow={name}` | delete a flow's runs; refused while any are active |
|
||||
| `GET` | `/runs/{id}/metrics?name=&stride=` | read metric series |
|
||||
| `GET` | `/runs/metrics/names` | list metric names across a selection |
|
||||
| `GET` | `/runs/series/compare?ids=a,b,c&metric=&x=` | compare curves by step, time, or another metric |
|
||||
| `GET` | `/runs/export/metrics`, `/runs/export/runs` | stream CSV or JSONL |
|
||||
|
||||
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.
|
||||
Submissions return a queued run immediately. Invalid or undeclared parameters
|
||||
return `422` before execution. Optional `draft` and `no_cache` flags select
|
||||
unpublished code or skip stage caching.
|
||||
|
||||
`/runs/import` takes `{"runs": [...]}`. Each entry carries `flow`,
|
||||
`external_id`, `params`, `seed`, `status` (`ok`, `error` or `cancelled`),
|
||||
`created_at`, `started_at`, `finished_at`, `result`, `metrics` (`name`,
|
||||
`step`, `ts`, `value`), `artifacts` (`name`, `filename`, `media_type`,
|
||||
`content_base64`), `labels` and `group_id`. The parameters are completed and
|
||||
checked as a submit's are, the run is stored with the cause `import` and an
|
||||
empty commit and code digest, and nothing is queued. The request is checked
|
||||
whole before anything is written, and an `external_id` already imported
|
||||
answers with that run and `"created": false`.
|
||||
History filters include `flow`, `status`, `group`, `digest`, `since`,
|
||||
`before`, `limit`, and `offset`. Rows arrive newest first; use the last
|
||||
row's `created_at` as `before` for stable pagination.
|
||||
|
||||
`?digest=` filters by the hash of the parameters, which is how you find "every
|
||||
run that used exactly this configuration".
|
||||
Exports also accept `ids` and `until`, with `format=csv` or `jsonl`.
|
||||
The metrics export is a long table; the runs export is one row per run.
|
||||
Use `params` and `metrics` to choose columns, including dotted paths into
|
||||
record outputs.
|
||||
|
||||
`?before=` is how a long history is paged: rows come newest first, so handing
|
||||
back the last row's `created_at` reads the next page whatever landed
|
||||
meanwhile, which `?offset=` cannot, since a run submitted between two pages
|
||||
shifts every row down one. `?since=` is inclusive and bounds the other end.
|
||||
|
||||
Both exports stream `csv` (the default) or `jsonl`, and take the selection the
|
||||
history takes plus `?ids=a,b,c`, `?since=` and `?until=`. `export/runs` puts
|
||||
the inputs that *vary* across the selection in `param.` columns (the sweep
|
||||
axis) unless `?params=` names them, and the run's numbers in `metric.`
|
||||
columns. Both are dotted paths into whatever a node returned, so
|
||||
`?metrics=final_metrics.train_loss` selects a field of a record and the
|
||||
defaults reach every number inside one. A key with a dot in its own name, such
|
||||
as `-1.0`, cannot be addressed that way and gets no column. The run id is on every row of both, which is what makes an exported
|
||||
file a join back to the run rather than a loose table.
|
||||
|
||||
`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).
|
||||
Import takes `{"runs": [...]}`, records completed results without executing
|
||||
code, and deduplicates by `external_id`. See
|
||||
[Runs](../concepts/runs.md) for examples, artifacts, caching, and exports.
|
||||
|
||||
## 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
|
||||
curl -X PUT "$FLUKSIO/artifacts?name=model.pt" \
|
||||
-H "Authorization: Bearer $TOKEN" --data-binary @model.pt
|
||||
curl "$FLUKSIO/artifacts/<digest>" \
|
||||
-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.
|
||||
The upload returns a reference with the content digest. Identical bytes are
|
||||
stored once. Node code uses `save_artifact` and `load_artifact` instead.
|
||||
|
||||
## Dashboards and panels
|
||||
|
||||
| Method | Path | What |
|
||||
| Method | Path | Action |
|
||||
|---|---|---|
|
||||
| `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 |
|
||||
| `POST` | `/dashboards/from-flow/{flow}` | build `{flow}_results` from a batch flow's declared ports — a chart per streamed metric, a stat per output. 409 if it already exists |
|
||||
| `GET` | `/dashboards/` | list dashboards |
|
||||
| `GET` | `/dashboards/{name}?draft=true` | read a draft; omit the query for published content |
|
||||
| `POST` | `/dashboards/{name}` | create |
|
||||
| `POST` | `/dashboards/from-flow/{flow}` | create a batch flow's results dashboard |
|
||||
| `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 |
|
||||
| `POST` | `/dashboards/{name}/publish`, `/dashboards/{name}/discard`, `/dashboards/{name}/rename` | publish, discard, or rename |
|
||||
| `GET`, `PUT` | `/panels/` | read or update panel assignments |
|
||||
| `POST` | `/panels/pair` | start device pairing |
|
||||
| `GET` | `/panels/pair/{code}` | poll pairing with its `secret` |
|
||||
| `POST` | `/panels/{id}/pair` | approve the pairing |
|
||||
| `POST` | `/panels/{id}/unpair` | revoke the panel credential |
|
||||
|
||||
## Secrets, modules, alerts
|
||||
## Secrets, modules, and 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. Secrets and `POST /modules/apply` are a superuser's, and so is
|
||||
what a connector keeps across restarts: `GET` or `DELETE
|
||||
/connectors/{node_type}/state`, or `DELETE /connectors/{node_type}/state/{key}`
|
||||
for one key (see [the connector contract](../reference/connector-contract.md#keeping-state-across-restarts)).
|
||||
|
||||
## Observability
|
||||
|
||||
| Path | What |
|
||||
|---|---|
|
||||
| `/observability/summary` | engine health — always 200, degraded or not — and the `version` it is running |
|
||||
| `/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; narrows by `?flow=`, `?run=`, `?since=`, `?until=` |
|
||||
| `/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 |
|
||||
| Method | Path | Action |
|
||||
|---|---|---|
|
||||
| `GET` | `/workers` | what is attached, its labels and how busy it is |
|
||||
| `POST` | `/workers/tokens` | mint a worker credential with its name and labels (superuser; shown once) |
|
||||
| `GET` | `/workers/tokens` | the worker credentials minted, without the tokens (superuser) |
|
||||
| `POST` | `/workers/tokens/{jti}/revoke` | refuse one from now on and drop a worker attached with it (superuser) |
|
||||
| `GET` | `/workers/runtime` | the node runner's source, for a host without pip |
|
||||
| `WS` | `/workers/attach` | where a worker dials in, with `Authorization: Bearer <worker token>` |
|
||||
| `GET` | `/secrets/` | list names only |
|
||||
| `PUT` | `/secrets/{name}` | set `{"value": "..."}` |
|
||||
| `GET` | `/modules/` | read installed packages and the manifest |
|
||||
| `POST` | `/modules/apply` | replace the manifest with `{"requirements": "numpy>=2\n"}` |
|
||||
| `GET`, `PUT` | `/alerts/config` | read or update alert configuration |
|
||||
| `POST` | `/alerts/test/{channel}` | test a channel |
|
||||
|
||||
See [Remote workers](workers.md).
|
||||
Secrets and package changes require a superuser. Applying a manifest replaces
|
||||
the whole managed environment's package list. Adopted environments are read-only
|
||||
here; install their packages yourself.
|
||||
|
||||
Connector state keys can also be listed and cleared by a superuser; see
|
||||
[the connector contract](../reference/connector-contract.md#keeping-state-across-restarts).
|
||||
|
||||
## Observability and workers
|
||||
|
||||
| Method | Path | Action |
|
||||
|---|---|---|
|
||||
| `GET` | `/observability/summary` | health and engine version; always returns `200` |
|
||||
| `GET` | `/observability/timeseries`, `/observability/flows` | execution metrics or flow rollups |
|
||||
| `GET` | `/observability/runs`, `/observability/events`, `/observability/dead-letter` | cascades, events, or abandoned work |
|
||||
| `GET` | `/utils/health/` | deep health check; fails on loop or state-backend problems |
|
||||
| `GET` | `/workers`, `/workers/resources` | attached workers and resource availability |
|
||||
| `GET`, `POST` | `/workers/tokens` | list or mint worker credentials; superuser only |
|
||||
| `POST` | `/workers/tokens/{jti}/revoke` | revoke a worker |
|
||||
| `GET` | `/workers/runtime` | read node-runner source |
|
||||
| `WS` | `/workers/attach` | attach with a worker token |
|
||||
| `GET`, `POST` | `/flavors/` | list or create resource sizes |
|
||||
| `PATCH`, `DELETE` | `/flavors/{name}` | update or delete a size |
|
||||
|
||||
Changing flavors requires a superuser. See [Remote workers](workers.md).
|
||||
|
||||
## Live events
|
||||
|
||||
```text
|
||||
ws://127.0.0.1:8000/api/v1/flows/ws
|
||||
```
|
||||
Connect to `ws://127.0.0.1:8000/api/v1/flows/ws` with an
|
||||
`Authorization: Bearer <access-token>` header.
|
||||
|
||||
A client that can set headers sends `Authorization: Bearer <access token>` on
|
||||
the handshake. A browser cannot, so it first calls `POST /flows/ws-ticket` and
|
||||
opens `/flows/ws?ticket=<ticket>`: a ticket is good for one connect, within 30
|
||||
seconds, so the URL that access logs keep is worth nothing afterwards.
|
||||
`?token=` is still accepted for one more release. The socket 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.
|
||||
Browsers first call `POST /flows/ws-ticket`, then connect with
|
||||
`?ticket=<ticket>`. Tickets are single-use and expire after 30 seconds.
|
||||
The socket sends a snapshot followed by node, value, health, and run events.
|
||||
|
||||
## Errors
|
||||
## Errors and client generation
|
||||
|
||||
| Code | Means |
|
||||
| Code | Meaning |
|
||||
|---|---|
|
||||
| `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 instance |
|
||||
| `400` | malformed request or refused operation |
|
||||
| `401` / `403` | missing authentication or permission |
|
||||
| `404` | resource not found |
|
||||
| `409` | version conflict, duplicate, or resource still in use |
|
||||
| `413` | artifact upload exceeds the configured limit |
|
||||
| `422` | invalid parameters, ports, or bindings |
|
||||
| `503` | subsystem unavailable |
|
||||
|
||||
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.
|
||||
For a version conflict, read `current_version`, reload, merge your edits, and
|
||||
save again. Other `409` responses describe their own conflict.
|
||||
|
||||
## 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 instance,
|
||||
from the machine it runs on.
|
||||
`make generate-client` regenerates the frontend SDK. To generate a client in
|
||||
another language, use the instance's `/api/v1/openapi.json` schema.
|
||||
|
||||
Reference in New Issue
Block a user