Workflows API
Multi-agent workflow pipelines and their runs.
There is no POST /workflows or PUT /workflows/{id} — no such routes exist in routes.rs, and the Action enum has no WorkflowCreate/WorkflowUpdate variant. Workflows enter the system only via install-from-package. To provision a workflow, install a WorkflowTemplate package via POST /catalog/install.
Endpoints
| Method | Path | Action | Description |
|---|---|---|---|
| GET | /workflows | WorkflowList | List installed workflow definitions |
| GET | /workflows/{id} | WorkflowStatus | Get a workflow definition |
| POST | /workflows/{id}/run | WorkflowRun | Start a run |
| GET | /workflows/{id}/runs | WorkflowList | List runs for one workflow |
| GET | /runs | WorkflowList | List runs across every installed workflow |
| GET | /runs/{id} | WorkflowStatus | Get a specific run's status |
| POST | /workflows/step | WorkflowRun | Legacy single-step execution (kept for backward compat) |
WorkflowRun is admin/operator/developer/service; WorkflowList/WorkflowStatus are broadly readable (admin/operator/developer/viewer/service/auditor).
GET /workflows
curl -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/workflows
Response (200) — WorkflowDefinition[]
{
"workflows": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "claims-pipeline",
"description": "End-to-end claims processing",
"steps": [
{
"name": "intake",
"agent": {"ByName": "claims-intake-agent"},
"prompt_template": "Process this claim: {{input}}",
"mode": "Sequential",
"timeout_secs": 120,
"error_mode": "Fail",
"output_var": "claim_data"
}
],
"created_at": "2026-06-04T10:00:00Z"
}
]
}
agent is {"ByName": "..."} or {"ById": "<uuid>"}. error_mode is "Fail", "Skip", or {"Retry": {"max_retries": N}}.
GET /workflows/{id}
Same shape as one entry of /workflows, plus admission_state:
{
"id": "a1b2c3d4-...",
"name": "claims-pipeline",
"description": "...",
"steps": [...],
"created_at": "2026-06-04T10:00:00Z",
"admission_state": "active"
}
admission_state is "active" (accepting new runs), "draining" (rejecting new runs, in-flight runs continue — entered by a suspend not exposed on this page), or "suspended" (no runs in flight, none admitted). null if the workflow has no admission-state record.
Error (400 — invalid ID)
{"error": {"category": "ValidationError", "message": "Invalid workflow ID format"}}
POST /workflows/{id}/run
curl -X POST -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
-H "Content-Type: application/json" \
-d '{"input": "New auto claim: rear-end collision on I-95, policy POL-2024-200"}' \
http://localhost:4200/workflows/a1b2c3d4-.../run
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
input | string | Yes | Initial input text for the workflow |
Response (201) — WorkflowRunStatus
{
"id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"workflow_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"workflow_name": "claims-pipeline",
"input": "New auto claim: rear-end collision on I-95...",
"state": "Running",
"step_results": [],
"output": null,
"error": null,
"started_at": "2026-06-04T10:15:00Z",
"completed_at": null
}
Note this is 201 Created, not 200. Poll GET /runs/{id} for completion.
Completed run (as later returned by GET /runs/{id})
{
"id": "c3d4e5f6-...",
"workflow_id": "a1b2c3d4-...",
"workflow_name": "claims-pipeline",
"input": "...",
"state": "Completed",
"step_results": [
{
"step_name": "intake",
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_name": "claims-intake-agent",
"output": "Claim data collected...",
"tokens_used": 412,
"duration_ms": 2300
}
],
"output": "Claim #CLM-2026-042 created. Routed to adjuster queue: auto-collision-moderate.",
"error": null,
"started_at": "2026-06-04T10:15:00Z",
"completed_at": "2026-06-04T10:15:04Z"
}
Note step_results[].step_name (not step), and each entry carries agent_id/agent_name/tokens_used.
GET /workflows/{id}/runs
curl -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
"http://localhost:4200/workflows/a1b2c3d4-.../runs?state=Completed"
Query Parameters
| Param | Type | Description |
|---|---|---|
state | string | Filter by RunState (see below) |
Response (200)
{"runs": [ /* WorkflowRunStatus[] */ ]}
GET /runs
Cross-workflow run listing (issue #634 Phase 6) — avoids fanning out /workflows/{id}/runs per installed workflow.
curl -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
"http://localhost:4200/runs?state=Running"
Same response/query shape as /workflows/{id}/runs, unfiltered by workflow.
GET /runs/{id}
curl -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
http://localhost:4200/runs/c3d4e5f6-a7b8-9012-cdef-123456789012
Full WorkflowRunStatus (same shape as the run-completion example above).
POST /workflows/step (legacy)
Executes a single agent turn directly, bypassing the workflow definition/run tracking entirely — kept for backward compatibility, not part of the current workflow model.
curl -X POST -H "Api-Version: v1" -H "Authorization: Bearer hzn_sk_..." \
-H "Content-Type: application/json" \
-d '{"target_agent": "550e8400-e29b-41d4-a716-446655440000", "input": "Process this claim"}' \
http://localhost:4200/workflows/step
Request Body (WorkflowStep)
| Field | Type | Required | Description |
|---|---|---|---|
target_agent | string (UUID) | Yes | Agent to execute the step |
input | string | Yes | Input payload |
timeout | integer (ms) | No | Optional timeout override |
Response (200) — WorkflowStepResult
{"output": "...", "pii_tokenized": false, "duration": 2100}
Run States
| State | Description |
|---|---|
Pending | Run created but not yet started |
Running | Currently executing steps |
Suspended | Paused, preserves position for later resume |
Completed | All steps finished successfully (terminal) |
Failed | Aborted due to a step failure per its error_mode (terminal) |
Escalated | Escalated to a human operator — outcome delivered, billable per ADR-033 (terminal) |
is_terminal() is Completed | Failed | Escalated — Failed is not the only terminal outcome.
Related
- catalog.md — installing
WorkflowTemplatepackages (the only way to create a workflow) - agents.md — the agents each step routes to
- usage-budget.md —
Completed/Escalatedruns feedGET /usage's cost totals