API workflow¶
The Axum API is mounted at /api/v2. Health is public; operational resources
require a bearer token, and mutating administrative surfaces require a
superuser. Output publication receipts return through the authenticated remote
control plane rather than a graph-facing HTTP callback.
Authenticate¶
Use the password setup printed once. It is not stored in .env.
export BASE=http://127.0.0.1:18080
export ADMIN_USER="${ADMIN_USER:-admin}"
export ADMIN_PASSWORD="${ADMIN_PASSWORD:?set to the password setup printed}"
LOGIN_BODY=$(jq -n \
--arg username "$ADMIN_USER" \
--arg password "$ADMIN_PASSWORD" \
'{username:$username,password:$password}')
export TOKEN=$(curl -fsS -X POST "$BASE/api/v2/login" \
-H 'Content-Type: application/json' \
-d "$LOGIN_BODY" \
| jq -er .access_token)
export AUTH="Authorization: Bearer $TOKEN"
curl -fsS "$BASE/api/v2/user/me" -H "$AUTH" | jq .
Access and refresh tokens carry jti claims. Refresh rotates the refresh token; logout blacklists token hashes. Public user responses never include password hashes.
Resource order¶
Project and profile¶
curl -fsS -X POST "$BASE/api/v2/project-configs" \
-H "$AUTH" -H 'Content-Type: application/x-yaml' \
--data-binary @config/examples/minimal_survey.v2.yaml | jq .
curl -fsS -X POST "$BASE/api/v2/deployment-profiles" \
-H "$AUTH" -H 'Content-Type: application/json' \
-d @profile.json | jq .
Project uploads create immutable versions. Profile responses are redacted and future executions pin the selected revision.
List installed Slurm SSH credential slots (names and file presence only; never key material) before choosing deployment.ssh_credential:
curl -fsS "$BASE/api/v2/slurm/credentials" -H "$AUTH" | jq .
curl -fsS "$BASE/api/v2/slurm/credentials/hpc" -H "$AUTH" | jq .
Init, import, and copy-id remain CLI. Empty credential roots return { "slots": [] }.
Source and discovery¶
SOURCE=$(curl -fsS -X POST "$BASE/api/v2/sources" \
-H "$AUTH" -H 'Content-Type: application/json' \
-d '{"project_module":"minimal_survey","source_identifier":"source-1","enabled":true}')
SOURCE_ID=$(jq -r .uuid <<<"$SOURCE")
curl -fsS -X POST "$BASE/api/v2/sources/discover" \
-H "$AUTH" -H 'Content-Type: application/json' \
-d '{"project_module":"minimal_survey","source_identifier":"source-1"}' | jq .
curl -fsS "$BASE/api/v2/sources/$SOURCE_ID/status" -H "$AUTH" | jq .
curl -fsS "$BASE/api/v2/sources/$SOURCE_ID/metadata" -H "$AUTH" | jq .
curl -fsS "$BASE/api/v2/sources/$SOURCE_ID/events" -H "$AUTH" | jq .
sources/discover marks matching enabled sources for rediscovery. The scheduler and workers perform the durable claim/query/persistence path asynchronously.
Metadata is grouped by the neutral group_key field. Each
metadata_json payload contains records; every prepared record has a
record_id. Those names are stable Core API fields regardless of how a project
renames collections in its emitted manifest.
Prepare and execute¶
Use the same body for preflight and creation:
cat > /tmp/execution.json <<'JSON'
{
"project_module": "minimal_survey",
"sources": [
{"source_identifier": "source-1", "groups": ["group-1"]}
],
"archive_name": "catalog",
"deployment_profile_name": "local-rest"
}
JSON
curl -fsS -X POST "$BASE/api/v2/executions/prepare" \
-H "$AUTH" -H 'Content-Type: application/json' \
-d @/tmp/execution.json | jq .
EXEC=$(curl -fsS -X POST "$BASE/api/v2/executions" \
-H "$AUTH" -H 'Content-Type: application/json' \
-H 'Idempotency-Key: operator-intent-20260822-001' \
-d @/tmp/execution.json)
EXEC_ID=$(jq -r .uuid <<<"$EXEC")
curl -fsS -X POST "$BASE/api/v2/executions/$EXEC_ID/execute" \
-H "$AUTH" -H 'Content-Type: application/json' \
-d '{"do_stage":false,"do_submit":false}' | jq .
Creation keys are scoped to the authenticated user and one request body. The
first request returns 201, an exact retry returns the same execution with
200, and reuse with different content returns 409. Persist the key before
sending the request so a lost response can be resumed safely.
Execution start is intrinsically idempotent for the execution UUID. Exact
queued, running, and completed retries return 202 with the same job ID;
different do_stage/do_submit flags return 409. do_submit:false is a
preparation-only boundary. Use do_submit:true only after the pinned profile
doctor passes and real backends are deliberately enabled.
sources[].groups is optional; omit it to select all ready groups for that
source. A supplied list is validated against persisted group_key values
during preparation.
Inspect exact state instead of polling only the compact status:
curl -fsS "$BASE/api/v2/executions/$EXEC_ID/status" -H "$AUTH" | jq .
curl -fsS "$BASE/api/v2/executions/$EXEC_ID/ledger-snapshot" -H "$AUTH" | jq .
curl -fsS "$BASE/api/v2/executions/$EXEC_ID/observations" -H "$AUTH" | jq .
curl -fsS "$BASE/api/v2/executions/$EXEC_ID/artifacts" -H "$AUTH" | jq .
curl -fsS "$BASE/api/v2/executions/$EXEC_ID/events" -H "$AUTH" | jq .
When the pinned project requires durable output verification (in progress), use the terminal
beampipe-publish application from standalone beampipe-palette. The trusted
Slurm path retrieves its canonical receipt over authenticated SFTP after
scheduler success, so the remote graph needs no route or credential back to
Core. There is no publisher callback or execution token to put in graph or
scheduler artifacts. The complete pull, inventory, ordering, and
idempotent-retry contract is in
Output verification (in progress).
Clean-break field migration¶
Core v2 no longer accepts project-specific selection aliases. API clients and saved request bodies must use:
| Resource | Field |
|---|---|
| Execution source selection | sources[].groups |
| Archive metadata response | group_key |
| Prepared item identity | record_id |
| Stored items within a group | metadata_json.records |
Provider terms may still appear as ordinary project data or explicitly renamed manifest output fields. They do not change request or persistence schemas.
Contract¶
The generated API schema is the field-level source of truth. Export it after Rust request/response changes:
Swagger UI and JSON are also served by the running API at /api/v2/docs and /api/v2/openapi.json when documentation is enabled.