REST API
The run-centric HTTP surface — start, inspect, cancel, signal, and stream runs.
Everything on the platform is reachable through a run-centric REST API. All requests are tenant-scoped and authenticated with a bearer token:
Authorization: Bearer iw_live_…
Content-Type: application/jsonPropagate traceparent (W3C trace context) on writes if you want your caller's trace joined to
the run's spans.
Errors
Errors use one envelope everywhere. Denials are explicit — the platform fails closed and tells you why:
{
"error": {
"code": "acl_denied",
"message": "Principal lacks execute on workflow:checkout-flow.",
"request_id": "req_01J9…"
}
}Start a run
POST /v1/runs
Idempotency-Key: idem_9f2c41 (optional — same key returns the existing run){
"workflow_id": "checkout-flow",
"workflow_version": "v2.4",
"input": { "order_id": "ord_28843", "customer_tier": "enterprise" }
}workflow_version is optional — omitting it runs the active version. Response 201:
{
"run_id": "run_8f31a2",
"state": "running",
"workflow_id": "checkout-flow",
"workflow_version": "v2.4",
"started_at": "2026-07-04T18:22:31Z"
}Inspect runs
GET /v1/runs list runs (filter by status, trigger, time range; cursor-paginated)
GET /v1/runs/{run_id} run status + node summary
GET /v1/runs/{run_id}/result the workflow result (409 while still running)
GET /v1/runs/{run_id}/history node-by-node execution history (the trace inspector's source)Run state is one of queued · running · retrying · succeeded · failed · cancelled.
Cancel
POST /v1/runs/{run_id}/cancelCooperative by default: in-flight steps clean up and compensations run. Idempotent — cancelling a terminal run is a no-op. Operators can force-terminate from the console.
Signals
POST /v1/runs/{run_id}/signals/{name}{ "request_id": "apr_114", "payload": { "approved": true, "note": "LGTM" } }Signals feed running workflows: resolve a human-approval node, deliver mid-run data, steer a
branch. Structured input requests validate payload against the schema the node registered;
delivery is idempotent by (run_id, request_id).
Stream events (SSE)
GET /v1/runs/{run_id}/events
Accept: text/event-stream
Last-Event-ID: 41 (optional — resume after a disconnect, no gaps)event: node_started
data: {"run_id":"run_8f31a2","node":"coder","seq":7}
event: node_completed
data: {"run_id":"run_8f31a2","node":"coder","latency_ms":1240,"tokens":18204,"cost_micro_usd":4100,"seq":8}
event: status_changed
data: {"run_id":"run_8f31a2","state":"succeeded","seq":12}The event catalog: status_changed · node_started · node_completed · node_failed · input_requested · input_resolved · signal_received · completed · failed · cancelled. Events are
strictly ordered per run (seq); the stream ends after a terminal event.
The console's live graph is this same feed — anything you watch there, your code can watch here.
