Management HTTP API
This page is generated from the management server’s route table (management.APIRoutes) by make docs-gen; make docs-check fails when it falls behind. Edit the source, not this page.
The CLI, the terminal UI and the web view are clients of one local HTTP API that the daemon serves. A tool of your own can call it the same way. The CLI reference covers the same operations as commands; the architecture pages describe what each does.
Reaching it
Section titled “Reaching it”The API is served over a Unix socket that only its owner can open: <state>/management.sock, where <state> is --data-dir, else $XDG_STATE_HOME/open-conduit, else ~/.local/state/open-conduit. --socket or OPEN_CONDUIT_SOCKET moves it. Every request carries an operator credential as Authorization: Bearer <token>. The owner’s credential is the token field of <state>/private/operator.token, a private (0600) JSON file of {"token_id", "token"}. open-conduit auth add NAME --role view|operate|admin --out FILE issues one for another operator.
TOKEN=$(jq -r .token ~/.local/state/open-conduit/private/operator.token)curl --unix-socket ~/.local/state/open-conduit/management.sock \ -H "Authorization: Bearer $TOKEN" http://localhost/v1/healthThe host name in the URL is not used. A dev server or proxy that forwards to the socket must add the header itself; never hand the token to a browser.
Each operator has a role, checked where the request is served, before anything is read or written: view reads, operate also runs controls and sends Events, and admin also applies and exports configuration and issues credentials. A request the role doesn’t allow is refused with 403 forbidden_role. The table below gives each endpoint’s least role. The /v1/toolbelt endpoints are not for operators: an execution reaches them with its own token, on the socket the host gives that execution, and an operator credential is refused there (403 wrong_credential_class). Everything an operator does is recorded as theirs (operator:<name>), from the credential, never from the request.
Envelopes
Section titled “Envelopes”A success is {"data": …}. A failure is {"error": {"code", "message", "request_id", "details"?}} with an HTTP status to match: 400 malformed or invalid_filter, 401 unauthenticated, 403 forbidden_role, 404 not_found, 409 revision_conflict, state_conflict or idempotency_conflict, 422 invalid_request or invalid_config (with details: each diagnostic’s path, code and message), and 503 unavailable (retry). Every response has an X-Request-Id header, the same as the error’s request_id. Messages never carry a backend’s or provider’s own error text.
Requests that change something
Section titled “Requests that change something”A POST takes a JSON body (Content-Type: application/json, at most 1 MiB) and no query string. Unknown, duplicate and null fields are refused as 400 malformed.
- Idempotency. An
Idempotency-Keyheader (1 to 128 printable ASCII characters) makes a request safe to retry: the same key with the same body, within 30 days, returns the first response (with anIdempotency-Expires-Atheader) rather than doing it again, and the same key with another body is409 idempotency_conflict. Where the table says required, a request without one is400 idempotency_key_required. A named operator’s keys are their own: two operators’ equal keys are two requests. - Revisions. A control on Work, an execution or a scope takes an optional
expected_revision(a decimal string, from the record’srevision). Given, the control acts only while the record is still at that revision (409 revision_conflictotherwise); omitted, it acts on the current one. - Input to Work.
POST /v1/eventswithscope_id, a namespacedtype, adelivery_idand optionaldata({"schema", "data"}),correlation_key,work_idorcausation_idsends an operator Event. The scope’s routes decide where it goes, and an Event withwork_idthat no route takes is that Work’s next input all the same, so Work made withPOST /v1/work(scope_id,kind,binding, optionalcontext) takes follow-up input this way. See routing.
IDs in paths
Section titled “IDs in paths”IDs are opaque and often contain / (manual/…, work/…, manual/…/attempt/1). Percent-encode the whole ID as one path segment: GET /v1/work/manual%2F3f2a…. An unencoded / makes another path, usually 404 not_found.
A list returns {"items": […], "next_cursor": …} (the Work list adds total). limit is 1 to 200 (50 by default). Pass next_cursor back as cursor, with the same filters, for the next page, until it is empty. A cursor is opaque, belongs to its list and filters, and expires after 15 minutes (410 cursor_expired: start again). Each filter is given at most once; an unknown or repeated one is 400 invalid_filter. with adds to each item what its own endpoint returns: GET /v1/work?with=actions,panels,runs (any of the three; limit at most 50 with it) and GET /v1/events?with=route.
Endpoints
Section titled “Endpoints”| Method | Path | Role | Idempotency-Key | Filters |
|---|---|---|---|---|
GET |
/v1/health |
view | – | – |
GET |
/v1/capacity |
view | – | – |
GET |
/v1/schema |
view | – | – |
GET |
/v1/scopes |
view | – | parent_id, enabled |
GET |
/v1/scopes/{id} |
view | – | – |
GET |
/v1/work |
view | – | scope_id, state, kind, parent_id, source, executor, updated_after, q, sort, with |
GET |
/v1/work/facets |
view | – | scope_id, state, kind |
GET |
/v1/work/{id} |
view | – | – |
GET |
/v1/work/{id}/actions |
view | – | – |
GET |
/v1/scopes/{id}/actions |
view | – | – |
GET |
/v1/work/{id}/panels |
view | – | – |
GET |
/v1/work/{id}/config-candidate |
view | – | – |
GET |
/v1/pages |
view | – | – |
GET |
/v1/extensions |
view | – | – |
GET |
/v1/scopes/{id}/panels |
view | – | – |
GET |
/v1/scopes/{id}/route/samples |
view | – | – |
GET |
/v1/events |
view | – | scope_id, work_id, type, after_sequence, with |
GET |
/v1/events/{id} |
view | – | – |
GET |
/v1/events/{id}/route |
view | – | – |
GET |
/v1/executions |
view | – | scope_id, work_id, state |
GET |
/v1/executions/{id} |
view | – | – |
GET |
/v1/waits |
view | – | scope_id, work_id, execution_id, state |
GET |
/v1/waits/{id} |
view | – | – |
GET |
/v1/runs |
view | – | scope_id, work_id, state, executor_binding, executor, work_kind, outcome |
GET |
/v1/runs/{id} |
view | – | – |
GET |
/v1/runs/{id}/live |
view | – | – |
GET |
/v1/doctor |
view | – | – |
GET |
/v1/config |
view | – | – |
GET |
/v1/config/export |
admin | – | – |
GET |
/v1/artifacts |
view | – | work_id, execution_id, kind |
GET |
/v1/artifacts/{id}/content |
view | – | – |
POST |
/v1/events |
operate | required | – |
POST |
/v1/work |
operate | required | – |
POST |
/v1/work/{id}/cancel |
operate | required | – |
POST |
/v1/work/{id}/retry |
operate | required | – |
POST |
/v1/work/{id}/wake |
operate | required | – |
POST |
/v1/work/{id}/rebind |
operate | required | – |
POST |
/v1/work/{id}/hold |
operate | required | – |
POST |
/v1/work/{id}/interrupt |
operate | required | – |
POST |
/v1/work/{id}/release |
operate | required | – |
POST |
/v1/work/{id}/attach |
operate | required | – |
POST |
/v1/work/{id}/container-attach |
operate | required | – |
POST |
/v1/work/{id}/container-detach |
operate | required | – |
POST |
/v1/work/{id}/actions/{provider}/{action} |
operate | required | – |
POST |
/v1/scopes/{id}/reconcile |
operate | required | – |
POST |
/v1/scopes/{id}/route/trace |
view | optional | – |
POST |
/v1/scopes/{id}/actions/{provider}/{action} |
operate | required | – |
POST |
/v1/executions/{id}/cancel |
operate | required | – |
POST |
/v1/events/{id}/skip |
operate | required | – |
POST |
/v1/events/{id}/reroute |
operate | required | – |
POST |
/v1/config/validate |
view | optional | – |
POST |
/v1/config/apply |
admin | required | – |
POST |
/v1/auth/rotate |
operate | optional | – |
GET |
/v1/auth/operators |
view | – | – |
POST |
/v1/auth/operators |
admin | optional | – |
POST |
/v1/auth/revoke |
operate | required | – |
POST |
/v1/toolbelt/call |
execution | optional | – |
GET |
/v1/toolbelt/guidance |
execution | – | – |
GET |
/v1/toolbelt/serving |
execution | – | – |