Orchestrations Commands
See Orchestrations module docs for permissions and data model.
soat create-orchestration
Create an orchestration
- Method:
POST - Path:
/api/v1/orchestrations
Usage
soat create-orchestration --name <string> --nodes <array<object>> --edges <array<object>>
Options
--project-id
Public ID of the project. Optional when authenticating with a project-scoped API key, which defaults to the key's project; required otherwise.
- Source:
body - Required: no
- Type:
string
--name
Human-readable name.
- Source:
body - Required: yes
- Type:
string
--description
—
- Source:
body - Required: no
- Type:
string \| null
--nodes
The graph's nodes. Each id is unique and is what edges and nodes.<id> state references name; a node with no incoming edge starts the run.
- Source:
body - Required: yes
- Type:
array<object>
--edges
Directed edges between node ids. Every from/to must name a node in nodes, and the graph must be acyclic unless it contains a loop node. A node with several outgoing edges activates every target in parallel. [] for a graph of independent nodes.
- Source:
body - Required: yes
- Type:
array<object>
--state-schema
—
- Source:
body - Required: no
- Type:
object
--input-schema
—
- Source:
body - Required: no
- Type:
object
--output-mapping
The shape of a completed run's output, owned by the orchestration rather than by its terminal node ids. Each key is an output field (a dotted key such as summary.title builds a nested object); each value is JSON Logic (https://jsonlogic.com) evaluated against \{ "state": <final run state> \}, which includes state.input and state.nodes.<id>. A missing path maps to null; a mapping that throws fails the run. Null (or omitted) keys output by terminal node id. Versioned with the graph; null on update clears it.
- Source:
body - Required: no
- Type:
object<string, unknown> - Example:
\{"summary":\{"var":"state.summary"\},"answer":\{"var":"state.nodes.answer.content"\}\}
--version-label
Optional tag for the version this create archives, e.g. initial.
- Source:
body - Required: no
- Type:
string - Example:
initial
soat list-orchestrations
List orchestrations
- Method:
GET - Path:
/api/v1/orchestrations
Usage
soat list-orchestrations
Options
--project-id
Filter by project public ID
- Source:
query - Required: no
- Type:
string
soat validate-orchestration
Validate an orchestration graph
- Method:
POST - Path:
/api/v1/orchestrations/validate
Usage
soat validate-orchestration
Options
--nodes
The graph's nodes. Each id is unique and is what edges and nodes.<id> state references name; a node with no incoming edge starts the run. Checked exactly as create checks them, without persisting.
- Source:
body - Required: no
- Type:
array<object>
--edges
Directed edges between node ids. Every from/to must name a node in nodes, and the graph must be acyclic unless it contains a loop node. A node with several outgoing edges activates every target in parallel. Checked exactly as create checks them, without persisting.
- Source:
body - Required: no
- Type:
array<object>
--input-schema
Optional JSON Schema for run inputs; its top-level properties seed state.
- Source:
body - Required: no
- Type:
object
soat get-queue-stats
Get orchestration queue stats
- Method:
GET - Path:
/api/v1/orchestrations/queue/stats
Usage
soat get-queue-stats
Options
This command has no options.
soat list-queue-stats-projects
List the projects with queued orchestration work
- Method:
GET - Path:
/api/v1/orchestrations/queue/stats/projects
Usage
soat list-queue-stats-projects
Options
This command has no options.
soat get-orchestration
Get an orchestration
- Method:
GET - Path:
/api/v1/orchestrations/{orchestration_id}
Usage
soat get-orchestration
Options
This command has no options.
soat update-orchestration
Update an orchestration
- Method:
PATCH - Path:
/api/v1/orchestrations/{orchestration_id}
Usage
soat update-orchestration
Options
--name
—
- Source:
body - Required: no
- Type:
string
--description
—
- Source:
body - Required: no
- Type:
string \| null
--nodes
The graph's nodes. Each id is unique and is what edges and nodes.<id> state references name; a node with no incoming edge starts the run. Replaces the stored list; omitted, the stored nodes are kept and validated against the new edges.
- Source:
body - Required: no
- Type:
array<object>
--edges
Directed edges between node ids. Every from/to must name a node in nodes, and the graph must be acyclic unless it contains a loop node. A node with several outgoing edges activates every target in parallel. Replaces the stored list; omitted, the stored edges are kept and validated against the new nodes.
- Source:
body - Required: no
- Type:
array<object>
--state-schema
—
- Source:
body - Required: no
- Type:
object
--input-schema
—
- Source:
body - Required: no
- Type:
object
--output-mapping
The shape of a completed run's output, owned by the orchestration rather than by its terminal node ids. Each key is an output field (a dotted key such as summary.title builds a nested object); each value is JSON Logic (https://jsonlogic.com) evaluated against \{ "state": <final run state> \}, which includes state.input and state.nodes.<id>. A missing path maps to null; a mapping that throws fails the run. Null (or omitted) keys output by terminal node id. Versioned with the graph; null on update clears it.
- Source:
body - Required: no
- Type:
object<string, unknown> - Example:
\{"summary":\{"var":"state.summary"\},"answer":\{"var":"state.nodes.answer.content"\}\}
--version-label
Optional tag for the version this write archives, e.g. pre-rewire. Ignored when the write changes no graph field, since no version is archived.
- Source:
body - Required: no
- Type:
string - Example:
pre-rewire
--expected-version
Refuses the write unless the resource is at this version.
- Source:
body - Required: no
- Type:
unknown
soat delete-orchestration
Delete an orchestration
- Method:
DELETE - Path:
/api/v1/orchestrations/{orchestration_id}
Usage
soat delete-orchestration
Options
This command has no options.
soat list-orchestration-versions
List an orchestration's graph versions
- Method:
GET - Path:
/api/v1/orchestrations/{orchestration_id}/versions
Usage
soat list-orchestration-versions
Options
This command has no options.
soat get-orchestration-version
Fetch an archived orchestration version
- Method:
GET - Path:
/api/v1/orchestrations/{orchestration_id}/versions/{version}
Usage
soat get-orchestration-version --version <integer>
Options
--version
The archived version number
- Source:
path - Required: yes
- Type:
integer
soat restore-orchestration-version
Restore an archived orchestration graph
- Method:
POST - Path:
/api/v1/orchestrations/{orchestration_id}/versions/{version}/restore
Usage
soat restore-orchestration-version --version <integer>
Options
--version
The archived version number
- Source:
path - Required: yes
- Type:
integer
--label
Optional tag for the version the restore creates. Defaults to restored from v<version>.
- Source:
body - Required: no
- Type:
string - Example:
rollback to pre-incident graph
soat start-orchestration-run
Start an orchestration run
- Method:
POST - Path:
/api/v1/orchestration-runs
Usage
soat start-orchestration-run --orchestration-id <string>
Options
--orchestration-id
Orchestration to run (orch_...).
- Source:
body - Required: yes
- Type:
string - Example:
orch_V1StGXR8Z5jdHi6B
--input
Initial state for the run (merged with orchestration defaults).
- Source:
body - Required: no
- Type:
object
--tool-context
Key-value pairs forwarded as X-Soat-Context-<key> headers on every http, mcp and builtin tool call made by an agent node of this run — including the agents of any child run a loop or sub_orchestration node starts. The header name is X-Soat-Context- plus the key verbatim; no character is re-cased. The bag is stored on the run and re-read on every step, so it survives an awaiting_input pause, a sleeping wait, a background worker drive and a crash redrive. It is write-only: a run is a record every principal who may read runs can read, and a credential in it is not theirs to see, so it is never returned on one. It also does not outlive the run: reaching a terminal status (completed, failed, cancelled or expired) clears it. A key that is not a valid HTTP header name, or two keys that map to the same header, are rejected with 400 INVALID_TOOL_CONTEXT_KEY and no run is created. The reserved identity keys (session_id, actor_id, actor_external_id) are stripped at generation time — a caller cannot address them from here.
- Source:
body - Required: no
- Type:
object<string, string> - Example:
\{"ocaToken":"eyJhbGciOiJIUzI1NiJ9.abc"\}
--metadata
Caller-supplied key/value metadata attached to the run record for per-run attribution (e.g. which of your own tenants this run belongs to, or the dispatch batch that started it). Round-trips verbatim on every read of the run, on the list as well as the single read. The bag is caller-owned and no key is reserved: server-owned state (status, the pinned orchestration version, the trace, usage, artifacts, the run's own input and accumulated state) lives in its own top-level field and cannot be written from here. It is not merged into run state: no graph node sees it, and an input_schema never has to tolerate it — which is what makes it the place for an infrastructural label, rather than input. Keys are never transformed. It is not inherited by the child runs a loop or sub_orchestration node starts; each child carries whatever the graph gives it, which today is nothing.
- Source:
body - Required: no
- Type:
unknown - Example:
\{"tenant_account_id":"42","dispatch_batch":"nightly-2026-08-25"\}
--idempotency-key
Deduplication key, unique within the project, that makes a retry of an ambiguous failure safe. The first request under a key starts the run and answers 201; any later request carrying the same key answers 200 with that same run, whatever state it has reached — including a retry that arrives while the original is still running. The key is claimed by the run record and stays claimed for as long as the record exists, so it never silently expires and lets a second run through. orchestration_id, input, tool_context and metadata are the request the key names: reusing a key with any of them changed is 409 IDEMPOTENCY_KEY_REUSED rather than a replay of a run that does something else. wait is not part of that comparison — it says how the caller waits, not what the run is — so a retry may flip it.
- Source:
body - Required: no
- Type:
string - Example:
dispatch-2026-09-18-activation-42
--wait
When true, block until the run reaches a terminal (completed/failed) or awaiting_input state and return the settled run. When false (default), return immediately with status "queued" and execute the run in the background.
- Source:
body - Required: no
- Type:
boolean - Default:
false
soat list-orchestration-runs
List orchestration runs
- Method:
GET - Path:
/api/v1/orchestration-runs
Usage
soat list-orchestration-runs
Options
--project-id
Narrow the listing to one project (proj_...). A project-scoped key lists its own project without it.
- Source:
query - Required: no
- Type:
string
--orchestration-id
Filter by orchestration public ID (orch_...)
- Source:
query - Required: no
- Type:
string
--parent-orchestration-run-id
Filter to the runs one specific parent run's loop / sub_orchestration nodes started (run_...). This is how a caller holding a parent names the individual children behind its usage.
- Source:
query - Required: no
- Type:
string
--nested
Filter by whether the run was started by another run. false returns only the runs a caller started (no parent), which is the set to sum usage over; true returns only the runs a loop / sub_orchestration node started, across every parent. Omit to return both. Contradicting parent_orchestration_run_id with nested=false is a 400; any value other than true or false is a 400.
- Source:
query - Required: no
- Type:
boolean
--status
Filter by run status. Repeat the parameter to OR values — status=queued&status=running&status=sleeping&status=awaiting_input is the set still driving, which is how a caller finds live work without paging every run the project ever started. There is no non_terminal shorthand on purpose: which statuses count as live is the caller's policy. A value outside the enum, empty string included, is a 400.
- Source:
query - Required: no
- Type:
array<enum("queued", "running", "sleeping", "awaiting_input", "completed", "failed", "cancelled", "expired")> - Example:
["queued","running"]
soat cancel-orchestration-run
Cancel an orchestration run
- Method:
POST - Path:
/api/v1/orchestration-runs/{orchestration_run_id}/cancel
Usage
soat cancel-orchestration-run
Options
This command has no options.
soat pause-orchestration-run
Pause an orchestration run
- Method:
POST - Path:
/api/v1/orchestration-runs/{orchestration_run_id}/pause
Usage
soat pause-orchestration-run
Options
--reason
Why the run is being paused, surfaced on the parked run's required_action.reason and on pause_reason.
- Source:
body - Required: no
- Type:
string
soat submit-human-input
Submit human input
- Method:
POST - Path:
/api/v1/orchestration-runs/{orchestration_run_id}/human-input
Usage
soat submit-human-input --node-id <string>
Options
--node-id
ID of the human node to satisfy.
- Source:
body - Required: yes
- Type:
string
--output
Output/response provided by the human reviewer.
- Source:
body - Required: no
- Type:
object
soat resume-orchestration-run
Resume an orchestration run
- Method:
POST - Path:
/api/v1/orchestration-runs/{orchestration_run_id}/resume
Usage
soat resume-orchestration-run
Options
This command has no options.
soat get-orchestration-run
Get an orchestration run
- Method:
GET - Path:
/api/v1/orchestration-runs/{orchestration_run_id}
Usage
soat get-orchestration-run
Options
This command has no options.
soat list-orchestration-run-node-executions
List a run's node executions
- Method:
GET - Path:
/api/v1/orchestration-runs/{orchestration_run_id}/node-executions
Usage
soat list-orchestration-run-node-executions
Options
This command has no options.