Workflow & Multi-Agent Planning API
Execute workflow definitions and leverage multi-agent planning for complex task decomposition through the Orchestrator API.
Overview
This page focuses on the workflow execution endpoints rooted at /api/v1/workflows/execute and the related execution-history endpoints under /api/v1/workflows/executions.
If you are governing an external orchestrator such as LangGraph or CrewAI, use the Workflow Control Plane endpoints under /api/v1/workflows instead. See Workflow Control Plane for that model.
The Workflow API provides:
- Workflow Execution: Execute predefined workflows with sequential/parallel steps
- Multi-Agent Planning (MAP): LLM-powered task decomposition and execution
- Execution Tracking: Monitor workflow progress and retrieve results
Base URL: http://localhost:8080 (Agent Gateway)
Full request bodies, response schemas, and status codes for the endpoints below are in the generated Orchestrator API reference, rendered from the published OpenAPI spec. Use the links in the table to jump straight to an operation. Endpoints on this page without a reference link are not yet part of the published OpenAPI specs and are documented in full here.
| Method | Path | Purpose | Reference |
|---|---|---|---|
POST | /api/v1/workflows/execute | Execute a workflow definition | executeWorkflow |
GET | /api/v1/workflows/executions | List recent workflow executions | listWorkflowExecutions |
GET | /api/v1/workflows/executions/{id} | Get one workflow execution | getWorkflowExecution |
GET | /api/v1/workflows/executions/tenant/{tenant_id} | List executions for a tenant | getTenantWorkflowExecutions |
POST | /api/v1/plan | Submit a query for multi-agent planning | executePlan |
GET | /api/v1/plan/{id} | Get plan status | getPlanStatus |
GET | /api/v1/unified/executions/{id}/stream | Stream execution status via SSE | streamExecutionStatus |
The generated reference also covers the rest of the plan lifecycle — cancelPlan, resumePlan, rollbackPlan, getPlanVersions — and plan-step approvals: listPendingPlanApprovals, approveMAPPlanStep, rejectMAPPlanStep.
Authentication
All endpoints require:
Authorization: Basic base64(clientId:clientSecret)headerContent-Type: application/jsonheader (for POST requests)
The Agent gateway validates the credentials and stamps X-Org-ID, X-Tenant-ID, and X-Client-ID identity headers before forwarding to the Orchestrator; any client-supplied values for these headers are overwritten. The plan and workflow handlers treat the header-derived identity as authoritative over any org_id / tenant_id values in the request body.
Workflow and plan requests include a user context for audit trail:
user.id— Numeric user identifier. Required (non-zero) on/api/v1/planand/api/v1/plan/execute— a missing/zerouser.idis rejected with 401.user.email— User emailuser.role— User role for policy evaluation
Workflow Execution
POST /api/v1/workflows/execute (executeWorkflow) runs a workflow definition. The workflow.metadata.name, workflow.spec.steps, and user context are required; steps with depends_on wait for their dependencies while independent steps run in parallel.
curl -X POST http://localhost:8080/api/v1/workflows/execute \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)" \
-d '{
"workflow": {
"metadata": {
"name": "travel-booking",
"version": "1.0"
},
"spec": {
"steps": [
{
"name": "search_flights",
"type": "connector-call",
"connector": "amadeus-travel",
"operation": "query",
"statement": "search_flights",
"parameters": {
"origin": "SFO",
"destination": "CDG",
"departure_date": "2026-08-01"
}
},
{
"name": "search_hotels",
"type": "connector-call",
"connector": "amadeus-travel",
"operation": "query",
"statement": "search_hotels",
"parameters": {
"city": "Paris",
"check_in": "2026-08-01",
"check_out": "2026-08-07"
}
},
{
"name": "synthesize-results",
"type": "llm-call",
"prompt": "Summarize the flight and hotel options for a trip from SFO to Paris"
}
]
}
},
"input": {
"budget": 5000,
"currency": "USD"
},
"user": {
"id": 123,
"email": "[email protected]",
"role": "user"
}
}'
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
workflow.metadata.name | string | Yes | Workflow name (400 if missing) |
workflow.spec.steps | array | Yes | Array of workflow steps (400 if empty) |
input | object | No | Input data for the workflow |
user | object | No | User context for audit and policy evaluation (recommended) |
The org/tenant identity on the execution record comes from the gateway-set X-Org-ID / X-Tenant-ID headers, which override any values in user.
Step Types:
| Type | Description |
|---|---|
llm-call | Send prompt to an LLM provider (provider, model, max_tokens optional) |
connector-call | Execute a query or command via an MCP connector (connector, operation — query or execute — statement, parameters) |
api-call | Invoke a registered external API step |
conditional | Branch on a condition with if_true / if_false step lists |
function-call | Invoke a built-in function step |
An unknown step type fails the execution (500) with an unknown step type error. Steps run sequentially in array order — there is no depends_on field in the workflow-execution model.
Execution History
The response is the workflow execution object:
{
"id": "wf_1751971200_a1b2c3d4",
"workflow_name": "travel-booking",
"status": "completed",
"input": { "budget": 5000, "currency": "USD" },
"output": {
"final_result": "I found great options for your trip..."
},
"steps": [
{
"name": "search_flights",
"status": "completed",
"input": { "budget": 5000, "currency": "USD" },
"output": { "flights": [ {"airline": "Air France", "price": 850} ] },
"start_time": "2026-07-02T10:00:00Z",
"end_time": "2026-07-02T10:00:01Z",
"process_time": "1.234s"
},
{
"name": "synthesize-results",
"status": "completed",
"output": { "response": "I found great options for your trip..." },
"start_time": "2026-07-02T10:00:01Z",
"end_time": "2026-07-02T10:00:03Z",
"process_time": "2.123s"
}
],
"start_time": "2026-07-02T10:00:00Z",
"end_time": "2026-07-02T10:00:03Z",
}
Timing fields are start_time / end_time (RFC3339) on both the execution and each step; per-step elapsed time is the process_time duration string. A failed execution carries a top-level error field and the failing step's error.
Other responses:
| Status | Meaning |
|---|---|
| 202 | Execution paused for human approval (HITL-enabled deployments). Body is the execution object extended with approval_id, approval_status, paused_at_step, and paused_reason. |
| 400 | Invalid body, missing workflow name, or empty steps array |
| 500 | Workflow execution failed |
GET /api/v1/workflows/executions/{id}
Get details of a workflow execution.
Request:
curl http://localhost:8080/api/v1/workflows/executions/wf_1751971200_a1b2c3d4 \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)"
Response (200 OK):
Returns the same workflow execution object as POST /api/v1/workflows/execute (see above): id, workflow_name, status, input, output, steps (with start_time / end_time / process_time per step), start_time, end_time, user_context, and error when failed.
Errors: 404 when the execution is not found.
GET /api/v1/workflows/executions
List recent workflow executions.
Request:
curl "http://localhost:8080/api/v1/workflows/executions?limit=10" \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)"
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 10 | Number of executions to return. Non-positive or unparseable values fall back to 10. |
This endpoint accepts only limit; there is no offset or status filter.
Response (200 OK):
{
"executions": [
{
"id": "wf_1751971200_a1b2c3d4",
"workflow_name": "travel-booking",
"status": "completed",
"start_time": "2026-07-02T10:00:00Z",
"end_time": "2026-07-02T10:00:05Z",
...
}
],
"count": 1
}
Each entry is a full workflow execution object.
GET /api/v1/workflows/executions/tenant/{tenant_id}
List workflow executions for a specific tenant.
Request:
curl http://localhost:8080/api/v1/workflows/executions/tenant/my-tenant \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)"
Response (200 OK):
{
"tenant_id": "my-tenant",
"count": 5,
"executions": [ ... ]
}
GET /api/v1/workflows/executions/{id}/hitl-status
Get the human-in-the-loop status of an execution that may be paused for approval.
Response (200 OK):
{
"execution_id": "wf_1751971200_a1b2c3d4",
"status": "paused",
"approval_id": "0d0f7a9e-...",
"approval_status": "pending",
"paused_at_step": 1,
"paused_reason": "Policy requires human approval"
}
Errors: 404 execution not found; 503 when HITL is not enabled on the deployment.
Multi-Agent Planning (MAP)
MAP is a two-step flow: POST /api/v1/plan generates and stores a plan without executing it; POST /api/v1/plan/execute executes a stored plan. This lets you review (and optionally update) a plan before running it.
POST /api/v1/plan
Submit a complex query for LLM-powered task decomposition. The generated plan is stored (with an expiry) and returned — it is not executed by this endpoint.
Request:
curl -X POST http://localhost:8080/api/v1/plan \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)" \
-d '{
"query": "Plan a business trip from San Francisco to Paris for June 1-7, find flights under $1000 and 4-star hotels near the Eiffel Tower",
"domain": "travel",
"execution_mode": "auto",
"user": {
"id": 123,
"email": "[email protected]",
"role": "user"
},
"context": {
"budget": 5000,
"currency": "USD"
}
}'
The response includes the generated plan_id, the decomposed steps with their dependencies and target agents, the workflow_execution_id used to run the plan, the synthesized result, and execution metadata (per-task timing, execution mode).
| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Natural language query (400 if missing) |
domain | string | No | Domain hint: travel, healthcare, finance, generic (default). May also be supplied as context.domain. |
execution_mode | string | No | auto (default), parallel, sequential, balanced; Enterprise deployments additionally accept confirm and step. May also be supplied as context.execution_mode. 400 on an unknown/unavailable mode. |
user | object | Yes | User context — user.id must be a non-zero integer (401 otherwise) |
client | object | No | Client info for audit (id, name); org_id / tenant_id are overwritten from the gateway identity headers |
context | object | No | Additional context for planning |
Response (200 OK):
{
"success": true,
"plan_id": "plan_1751971200_a1b2c3d4",
"steps": [
{
"id": "step_1_search_flights",
"name": "search_flights",
"type": "connector-call",
"description": "Call amadeus-travel connector: search_flights",
"depends_on": [],
"agent": "amadeus-travel",
"parameters": {
"origin": "SFO",
"destination": "CDG",
"departure_date": "2026-08-01"
}
},
{
"id": "step_2_synthesize-results",
"name": "synthesize-results",
"type": "llm-call",
"description": "Create a summary of travel options",
"depends_on": []
}
],
"workflow_execution_id": "",
"result": null,
"metadata": {
"tasks_executed": 0,
"execution_mode": "auto",
"execution_time_ms": 4567,
"tasks": []
}
}
Because the plan has not run yet, workflow_execution_id is empty, result is null, tasks_executed is 0, and tasks is empty. Step type values are the planner's workflow step types (llm-call, connector-call, api-call); agent carries the connector name for connector steps.
Errors:
| Status | Meaning |
|---|---|
| 400 | Invalid body, missing query, or invalid execution_mode |
| 401 | Missing user authentication (user.id zero/absent) |
| 500 | Planning failed or plan storage failed |
| 503 | Planning engine or plan storage (database) not available |
Plan Status
GET /api/v1/plan/{id}
Get the status of a previously submitted plan, including step-level progress once it has executed.
Request:
curl http://localhost:8080/api/v1/plan/plan_1751971200_a1b2c3d4 \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)"
Response (200 OK):
{
"plan_id": "plan_1751971200_a1b2c3d4",
"execution_id": "plan_1751971200_a1b2c3d4",
"status": "completed",
"org_id": "acme-corp",
"tenant_id": "acme-prod-api",
"query": "Plan a business trip from San Francisco to Paris",
"domain": "travel",
"total_steps": 3,
"completed_steps": 3,
"progress_percent": 100,
"duration": "12s",
"created_at": "2026-07-02T10:00:00Z",
"started_at": "2026-07-02T10:00:01Z",
"completed_at": "2026-07-02T10:00:13Z",
"execution_mode": "auto",
"version": 1,
"execution_result": "I found excellent options for your Paris trip...",
"steps": [
{
"step_id": "step_1_search_flights",
"step_index": 0,
"step_name": "search_flights",
"step_type": "connector_call",
"status": "completed",
"started_at": "2026-07-02T10:00:01Z",
"ended_at": "2026-07-02T10:00:03Z",
"duration": "2s"
}
]
}
Additional optional fields when available: complexity, expires_at, workflow_definition, error, estimated_cost_usd, actual_cost_usd; per-step optional fields include error, cost_usd, model, provider, tokens_in, tokens_out.
Errors: 404 plan not found (also returned when the plan belongs to a different organization); 503 plan storage not available.
POST /api/v1/plan/execute
Execute a previously generated plan (step 2 of the MAP flow). The plan ID is passed inside context.plan_id.
Request:
curl -X POST http://localhost:8080/api/v1/plan/execute \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)" \
-d '{
"user": {
"id": 123,
"email": "[email protected]",
"role": "user"
},
"context": {
"plan_id": "plan_1751971200_a1b2c3d4"
}
}'
Before execution, tenant policies are evaluated against the plan (request_type: map_execution); a blocked plan returns 403 and is marked failed. Execution honors the plan's stored execution_mode. The synchronous execution window scales with step count (30s per step, capped at 300s by default; the cap is operator-configurable via AXONFLOW_MAP_MAX_TIMEOUT_SECONDS, clamped to 60–1800s).
Response (200 OK) — completed execution:
Same PlanResponse shape as POST /api/v1/plan, now populated: workflow_execution_id, result (the final synthesized output), metadata.tasks_executed, per-task metadata.tasks[] (name, status, time_ms), and policy_info (the policy evaluation result).
Response (202 Accepted) — paused for human approval (HITL-enabled deployments):
{
"plan_id": "plan_1751971200_a1b2c3d4",
"execution_id": "wf_1751971201_e5f6a7b8",
"status": "paused",
"paused_at_step": 1,
"paused_reason": "Policy requires human approval",
"approval_id": "0d0f7a9e-..."
}
Resume via the step approval endpoints below.
Response (200 OK) — confirm / step mode (Enterprise):
{
"plan_id": "plan_1751971200_a1b2c3d4",
"workflow_id": "wf_...",
"status": "awaiting_approval",
"current_step": 0,
"total_steps": 3,
"step_name": "search_flights",
"approval_info": { ... }
}
The plan advances one step per POST /api/v1/plan/{id}/resume call.
Errors:
| Status | Meaning |
|---|---|
| 400 | Invalid body or missing context.plan_id |
| 401 | Missing user authentication (user.id zero/absent) |
| 403 | Blocked by policy (body is a PlanResponse with success: false and policy_info), or confirm/step mode requested on a non-Enterprise deployment |
| 404 | Plan not found (or owned by another organization) |
| 409 | Plan already executed, or plan was cancelled |
| 410 | Plan expired before execution |
| 429 | CONCURRENT_EXECUTION_LIMIT — tier-based concurrent execution cap reached (body uses the {"error": {"code", "message"}} format) |
| 500 | Execution failed |
| 503 | Workflow engine or plan storage not available |
When usage approaches a tier limit (80%+), responses may carry X-AxonFlow-Tier-Warning and X-AxonFlow-Tier-Upgrade-URL headers.
POST /api/v1/plan/{id}/cancel
Cancel a pending or executing plan.
Request Body (optional): {"reason": "no longer needed"} — defaults to "cancelled via API".
Response (200 OK):
{
"success": true,
"plan_id": "plan_1751971200_a1b2c3d4",
"status": "cancelled",
"reason": "no longer needed",
"message": "no longer needed"
}
Errors: 404 plan not found; 409 when the plan cannot be cancelled (e.g. already terminal); 503 plan storage not available.
PUT /api/v1/plan/{id}
Update a stored plan with optimistic locking.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
version | integer | Yes | The plan version you read (optimistic-lock check) |
execution_mode | string | No | New execution mode (validated against the deployment tier) |
domain | string | No | New domain |
metadata | object | No | Replacement metadata |
Response (200 OK): {"success": true, "plan_id": "...", "version": 2, "status": "pending"}
Errors: 400 invalid body or execution mode; 404 plan not found; 409 version_conflict (body: {"error": "version_conflict", "message": "...", "plan_id": "..."}); 403 when tier plan/version limits are exceeded; 503 plan storage not available.
GET /api/v1/plan/{id}/versions
Get the version history of a plan.
Response (200 OK):
{
"plan_id": "plan_1751971200_a1b2c3d4",
"versions": [
{
"id": "...",
"plan_id": "plan_1751971200_a1b2c3d4",
"version": 1,
"snapshot": { ... },
"changed_at": "2026-07-02T10:00:00Z",
"change_type": "create",
"change_summary": "..."
}
]
}
Errors: 404 plan not found; 500 lookup failure; 503 plan storage not available.
POST /api/v1/plan/{id}/resume
Enterprise only. Advance a plan running in confirm or step mode by one step, or reject the pending step.
Request Body (optional): {"approved": true} — defaults to true. Sending false aborts the underlying workflow and marks the plan failed.
Responses (200 OK):
- Step executed, more steps remain:
{"plan_id", "workflow_id", "status": "awaiting_approval", "step_result", "next_step", "next_step_name", "total_steps"} - All steps completed:
{"plan_id", "workflow_id", "status": "completed", "step_result", "message"} - Rejected:
{"plan_id", "workflow_id", "status": "rejected", "message"}
Errors: 400 plan is not in executing status; 403 non-Enterprise deployment; 404 plan or active workflow not found; 500 step execution failed; 503 WCP executor or plan storage not available.
POST /api/v1/plan/{id}/rollback/{version}
Enterprise only. Roll a plan back to a previous version.
Response (200 OK):
{
"success": true,
"plan_id": "plan_1751971200_a1b2c3d4",
"version": 3,
"previous_version": 2,
"status": "pending",
"rolled_back_to": 1
}
Errors: 400 invalid target version; 403 non-Enterprise deployment or tier limits exceeded; 404 plan or version not found; 409 version_conflict; 503 plan storage not available.
MAP Step Approvals
When a MAP plan pauses for human approval (policy-driven HITL pause, or confirm/step mode), the pending step is approved or rejected through the plan-scoped approval endpoints. These require an Evaluation or Enterprise license — community deployments without an evaluation license receive 403.
POST /api/v1/plans/{id}/steps/{step_id}/approve
Request Body (optional):
| Field | Type | Description |
|---|---|---|
approved_by | string | Approver identity; falls back to the X-User-ID header, then "system" |
comment | string | Audit comment. For plans backed by a WCP workflow, comments shorter than 10 characters are replaced with a synthesized default |
Response (200 OK): a step-gate response shared with the Workflow Control Plane approve endpoint:
{
"workflow_id": "wf_...",
"plan_id": "plan_1751971200_a1b2c3d4",
"step_id": "step_1_search_flights",
"status": "approved",
"decision": "allow",
"approval_status": "approved",
"approval_id": "0d0f7a9e-...",
"approved_at": "2026-07-02T10:05:00Z",
"policies_matched": [ ... ],
"retry_context": {
"gate_count": 1,
"completion_count": 0,
"prior_completion_status": "none",
"prior_output_available": false,
"prior_output": null,
"prior_completion_at": null
},
"message": "Step approved"
}
retry_context is always present. For legacy in-memory pauses (no WCP workflow behind the plan), workflow_id is empty and retry_context is zero-valued.
Errors: 400 missing plan/step ID; 403 license tier; 404 no paused execution found for the plan; 409 the WCP-backed approval failed (e.g. step not pending approval); 503 HITL not enabled.
POST /api/v1/plans/{id}/steps/{step_id}/reject
Symmetric to approve. Body fields: rejected_by (same fallbacks) and reason. A rejection aborts the underlying workflow. The response is the same step-gate shape with status: "rejected", decision: "block", rejected_by / rejected_at, and reason. Same error codes as approve.
GET /api/v1/plans/approvals/pending
List steps currently awaiting approval across MAP-backed workflows for the calling tenant. Every entry has plan_id populated (the plan-plane counterpart of the WCP pending-approvals endpoint).
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
plan_id | string | (all) | Filter to a single plan |
limit | integer | 20 | Result cap |
Response (200 OK):
{
"pending_approvals": [
{
"workflow_id": "wf_...",
"workflow_name": "map-confirm-plan_1751971200_a1b2c3d4",
"plan_id": "plan_1751971200_a1b2c3d4",
"step_id": "step_1_search_flights",
"step_index": 0,
"step_name": "search_flights",
"step_type": "connector_call",
"decision": "require_approval",
"decision_reason": "...",
"approval_status": "pending",
"created_at": "2026-07-02T10:00:01Z"
}
],
"count": 1
}
pending_approvals is [] (never null) when empty; count is the total matching rows, which can exceed the page returned.
Errors: 400 missing tenant identity (the gateway sets it from your credentials); 403 license tier; 500 lookup failure; 503 workflow control plane unavailable.
Plan Cost Estimation
Cost estimation is rate-limited per tenant per UTC day by license tier (community: 10/day, evaluation: 100/day, enterprise: unlimited). Exceeding the limit returns 429 with code COST_ESTIMATE_LIMIT_EXCEEDED; approaching it (80%+) sets the X-AxonFlow-Tier-Warning and X-AxonFlow-Tier-Upgrade-URL response headers. Both endpoints require tenant identity (set by the gateway) and return 401 with code TENANT_REQUIRED without it.
POST /api/v1/plans/estimate
Estimate the cost of a set of steps without executing them.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
steps | array | Yes | Workflow steps to estimate (400 if empty) |
provider | string | No | Default provider applied to steps that don't set one |
model | string | No | Default model applied to steps that don't set one |
Response (200 OK):
{
"estimated_cost_usd": 0.0421,
"currency": "USD",
"breakdown": [
{
"step_name": "synthesize-results",
"provider": "openai",
"model": "gpt-4o",
"estimated_tokens_in": 1200,
"estimated_tokens_out": 400,
"estimated_cost_usd": 0.0421
}
]
}
breakdown is included only on Evaluation tier and above; community deployments receive the aggregate only.
GET /api/v1/plans/{id}/cost
Estimate the cost of an existing stored plan. Response adds plan_id to the same shape. Errors: 404 plan not found (or owned by another organization); 500 invalid stored workflow definition; 503 planning engine or plan storage not available.
Unified Execution API
The Unified Execution API provides a single interface for tracking both MAP plans and WCP workflows. It includes status queries and cancellation.
Base URL: http://localhost:8080 (Agent Gateway)
CORS: All endpoints answer OPTIONS preflight requests with 204 No Content, Access-Control-Allow-Origin: *, methods GET, POST, OPTIONS, and allowed headers Content-Type, Authorization, X-Tenant-ID, X-Org-ID.
Identity: The single-execution endpoints (get, cancel, stream) require both X-Tenant-ID and X-Org-ID — the Agent gateway sets them automatically from your Basic auth credentials. Requests without them are rejected with 401 UNAUTHORIZED, and an execution whose tenant/org doesn't match yours returns 404 (existence is not leaked across tenants).
Of the unified execution endpoints, only the SSE stream (GET /api/v1/unified/executions/{id}/stream) is part of the published OpenAPI specs. The list, get, and cancel endpoints below are not yet in the specs, so they are documented in full here.
GET /api/v1/unified/executions
List executions across both MAP plans and WCP workflows.
Request:
curl "http://localhost:8080/api/v1/unified/executions?limit=20&execution_type=wcp_workflow" \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)"
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max results (default: 20). The accepted ceiling is the smaller of 100 and the tier's execution-history limit (community: 50); values outside the range fall back to the default. |
offset | integer | Pagination offset (default: 0). Invalid values fall back to default. |
execution_type | string | Filter by type: map_plan or wcp_workflow |
status | string | Filter by status (see Execution Status Values) |
Headers:
| Header | Required | Description |
|---|---|---|
X-Tenant-ID (set by the gateway) | No | Filter by tenant ID (multi-tenancy) |
X-Org-ID (set by the gateway) | No | Filter by organization ID |
Response (200 OK):
{
"executions": [
{
"execution_id": "wf_abc123",
"execution_type": "wcp_workflow",
"name": "data-pipeline",
"status": "running",
"progress_percent": 66.7,
"total_steps": 3,
"current_step_index": 2,
"started_at": "2026-02-06T10:00:00Z",
"created_at": "2026-02-06T10:00:00Z",
"updated_at": "2026-02-06T10:00:03Z"
}
],
"total": 1,
"limit": 20,
"offset": 0,
"has_more": false
}
The has_more field indicates whether additional pages of results exist beyond the current offset.
GET /api/v1/unified/executions/{id}
Get detailed status of a specific execution. The {id} parameter accepts:
- An execution ID (direct lookup)
- A WCP workflow ID (prefix
wf_orwcp_) - A MAP plan ID (prefix
plan_)
The API tries multiple lookup strategies and returns the first match.
Request:
curl http://localhost:8080/api/v1/unified/executions/wf_abc123 \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)"
Response (200 OK):
{
"execution_id": "wf_abc123",
"execution_type": "wcp_workflow",
"name": "data-pipeline",
"source": "crewai",
"status": "running",
"current_step_index": 2,
"total_steps": 3,
"progress_percent": 66.7,
"started_at": "2026-02-06T10:00:00Z",
"duration": "5s",
"steps": [
{
"step_id": "step-1",
"step_index": 0,
"step_name": "Fetch Data",
"step_type": "tool_call",
"status": "completed",
"started_at": "2026-02-06T10:00:00Z",
"ended_at": "2026-02-06T10:00:01Z",
"duration": "1s",
"decision": "allow",
"model": "gpt-4",
"provider": "openai"
},
{
"step_id": "step-2",
"step_index": 1,
"step_name": "Process Data",
"step_type": "llm_call",
"status": "completed",
"started_at": "2026-02-06T10:00:01Z",
"ended_at": "2026-02-06T10:00:03Z",
"duration": "2s",
"decision": "allow",
"model": "gpt-4",
"provider": "openai"
},
{
"step_id": "step-3",
"step_index": 2,
"step_name": "Store Results",
"step_type": "tool_call",
"status": "running",
"started_at": "2026-02-06T10:00:03Z"
}
],
"metadata": {
"workflow_id": "wf_abc123"
},
"created_at": "2026-02-06T10:00:00Z",
"updated_at": "2026-02-06T10:00:03Z"
}
Example: WCP step with policy gate and approval flow:
{
"step_id": "gate-1",
"step_index": 0,
"step_name": "Policy Evaluation",
"step_type": "gate",
"status": "approval",
"started_at": "2026-02-06T10:00:00Z",
"decision": "require_approval",
"decision_reason": "Query accesses PII columns in production database",
"policies_matched": ["pii-protection", "prod-data-access"],
"approval_status": "pending",
"model": "gpt-4",
"provider": "openai",
"result_summary": "Awaiting manager approval for PII data access"
}
ExecutionStatus field reference:
| Field | Type | Omitted when empty |
|---|---|---|
execution_id | string | No |
execution_type | string | No |
name | string | No |
source | string | Yes |
status | string | No |
current_step_index | integer | No |
total_steps | integer | No |
progress_percent | float | No |
started_at | datetime | No |
completed_at | datetime | Yes |
duration | string | Yes |
steps | array | Yes |
error | string | Yes |
tenant_id | string | Yes |
org_id | string | Yes |
user_id | string | Yes |
client_id | string | Yes |
estimated_cost_usd | float | Yes |
actual_cost_usd | float | Yes |
metadata | object | Yes |
created_at | datetime | No |
updated_at | datetime | No |
StepStatus field reference:
| Field | Type | Omitted when empty |
|---|---|---|
step_id | string | No |
step_index | integer | No |
step_name | string | No |
step_type | string | No |
status | string | No |
started_at | datetime | Yes |
ended_at | datetime | Yes |
duration | string | Yes |
decision | string | Yes |
decision_reason | string | Yes |
policies_matched | string[] | Yes |
approval_status | string | Yes |
approved_by | string | Yes |
approved_at | datetime | Yes |
rejected_by | string | Yes |
rejected_at | datetime | Yes |
model | string | Yes |
provider | string | Yes |
cost_usd | float | Yes |
tokens_in | integer | Yes |
tokens_out | integer | Yes |
input | object | Yes |
output | object | Yes |
result_summary | string | Yes |
error | string | Yes |
GET /api/v1/unified/executions/{id}/stream
Stream real-time execution status updates via Server-Sent Events (SSE). The connection sends the current execution state immediately on connect, then pushes events as the execution progresses. The server closes the connection when the execution reaches a terminal state (completed, failed, cancelled, aborted, expired).
This endpoint is covered by the generated reference as streamExecutionStatus; the SSE semantics below are what you need to build a working client.
Request:
curl -N http://localhost:8080/api/v1/unified/executions/wf_abc123/stream \
-H "Accept: text/event-stream" \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)"
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Execution ID, WCP workflow ID, or MAP plan ID |
Headers:
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Basic base64(clientId:clientSecret) |
X-Tenant-ID, X-Org-ID | Yes (set by the gateway) | Tenant/org identity for ownership checks and per-tenant connection limits; missing identity is rejected |
Response Headers:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no
SSE Event Format:
Each event follows the standard SSE format with id, event, and data fields:
id: 1707220800000
event: execution.started
data: {"execution_id":"wf_abc123","execution_type":"wcp_workflow","name":"data-pipeline","status":"running",...}
The data payload is the full ExecutionStatus JSON object (same schema as the GET endpoint).
Event Types:
| Event | Description |
|---|---|
status | Initial execution state sent on connect |
execution.started | Execution has begun |
execution.completed | Execution completed successfully (terminal) |
execution.failed | Execution failed (terminal) |
execution.cancelled | Execution was cancelled (terminal) |
step.started | A step has started executing |
step.completed | A step completed successfully |
step.failed | A step failed |
step.decision | A policy gate decision was made on a step |
Connection Lifecycle:
- Client connects; server sends the current state as a
statusevent - If the execution is already terminal, the server closes the connection immediately
- While running, the server pushes events as execution state changes
- A
:keepaliveSSE comment is sent every 15 seconds to prevent proxy idle timeouts - On terminal event (
execution.completed,execution.failed,execution.cancelled), the server closes the connection - If the client disconnects, the server cleans up the subscription
Connection Limits:
Concurrent SSE connections are capped per tenant by license tier: 5 (community), 25 (evaluation), unlimited (enterprise). Exceeding the cap returns 429 Too Many Requests with an upgrade URL in the message.
Error Responses:
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Missing execution ID or missing tenant identity |
| 401 | UNAUTHORIZED | Missing tenant or org identity headers |
| 404 | NOT_FOUND | Execution not found (or owned by another tenant) |
| 429 | TOO_MANY_REQUESTS | Per-tenant SSE connection limit reached |
| 500 | INTERNAL_ERROR | Streaming not supported or lookup failure |
| 503 | SERVICE_UNAVAILABLE | Event streaming not available |
POST /api/v1/unified/executions/{id}/cancel
Cancel a running execution. Propagates to the appropriate subsystem:
- WCP workflows are aborted via
AbortWorkflow - MAP plans are cancelled via
CancelPlan
Request:
curl -X POST http://localhost:8080/api/v1/unified/executions/wf_abc123/cancel \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'my-app:my-secret' | base64)" \
-d '{"reason": "no longer needed"}'
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | No | Reason for cancellation (default: "cancelled via unified API") |
Response (200 OK):
Returns the full updated ExecutionStatus object (same schema as the GET endpoint):
{
"execution_id": "wf_abc123",
"execution_type": "wcp_workflow",
"name": "data-pipeline",
"status": "cancelled",
"current_step_index": 1,
"total_steps": 3,
"progress_percent": 33.3,
"started_at": "2026-02-06T10:00:00Z",
"completed_at": "2026-02-06T10:00:05Z",
"duration": "5s",
"steps": [...],
"created_at": "2026-02-06T10:00:00Z",
"updated_at": "2026-02-06T10:00:05Z"
}
If the cancellation succeeds but the refreshed status can't be fetched, a generic success body is returned instead: {"execution_id": "...", "status": "cancelled", "message": "Execution cancelled successfully"}.
Error Responses:
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Missing execution ID or unknown execution type |
| 401 | UNAUTHORIZED | Missing tenant or org identity headers |
| 404 | NOT_FOUND | Execution not found (or owned by another tenant) |
| 409 | CONFLICT | Execution already in terminal state |
| 500 | INTERNAL_ERROR | Subsystem cancellation failed |
Execution Status Values
Workflow Status
| Value | Description |
|---|---|
pending | Execution queued but not started |
running | Execution in progress |
completed | All steps completed successfully |
failed | One or more steps failed |
cancelled | Execution was cancelled via the cancel endpoint |
aborted | WCP workflow aborted (e.g., policy violation) |
expired | MAP plan expired before execution started |
Step Status Values
| Status | Description |
|---|---|
pending | Step not yet started |
running | Step currently executing |
completed | Step completed successfully |
failed | Step failed |
skipped | Step was skipped |
blocked | Step blocked by policy (WCP) |
approval | Step waiting for human approval (WCP) |
Step Types
| Type | Description |
|---|---|
llm_call | LLM provider invocation |
tool_call | External tool or function call |
connector_call | MCP connector invocation |
human_task | Human-in-the-loop task |
synthesis | MAP result synthesis step |
action | Generic action step |
gate | WCP policy gate evaluation |
Execution Flow
- An execution starts in
runningstatus when submitted - Direct workflow execution runs steps sequentially in array order; MAP plan execution parallelizes according to the plan's
execution_mode(auto/parallel/balanced) - If any step fails (and the workflow's soft-failure tolerance, when configured, is exceeded), the execution status becomes
failed - On success of all steps, the execution status becomes
completed
Gate Decisions
Policy gate decisions on steps (WCP):
| Decision | Description |
|---|---|
allow | Step allowed to proceed |
block | Step blocked by policy |
require_approval | Step requires human approval before proceeding |
Approval Status
Approval state when a step has decision: "require_approval":
| Status | Description |
|---|---|
pending | Awaiting approval |
approved | Approved by a user |
rejected | Rejected by a user |
expired | The approval timed out before review (terminal not-approved state, distinct from an explicit rejection) |
Error Responses
The two endpoint families use different error formats.
Workflow and MAP plan endpoints (/api/v1/workflows/*, /api/v1/plan*) return a flat envelope:
{
"success": false,
"error": "Plan not found: plan_1751971200_a1b2c3d4"
}
Common statuses across this family: 400 (invalid body / missing required field / invalid execution mode), 401 (missing user authentication on plan endpoints), 403 (policy block, license tier, or Enterprise-only mode), 404 (execution/plan not found), 409 (already executed, cancelled, or version conflict), 410 (plan expired), 429 (tier limits — these use the structured format below), 500 (execution/planning failure), 503 (subsystem not initialized).
Unified Execution API errors (and the tier-limit responses on plan endpoints) use the structured format:
{
"error": {
"code": "NOT_FOUND",
"message": "Execution not found: exec-123"
}
}
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Missing or invalid execution ID |
| 401 | UNAUTHORIZED | Missing tenant or org identity headers |
| 404 | NOT_FOUND | Execution not found |
| 409 | CONFLICT | Execution already in terminal state (cancel only) |
| 429 | TOO_MANY_REQUESTS / CONCURRENT_EXECUTION_LIMIT / COST_ESTIMATE_LIMIT_EXCEEDED | Tier limit reached |
| 500 | INTERNAL_ERROR | Internal server error |
| 503 | SERVICE_UNAVAILABLE | Event streaming not available |
Next Steps
- Agent Endpoints - Policy enforcement API
- MCP Connectors - Configure data connectors
- Integration Guides - Framework integrations
Operational Readiness Checklist
Before relying on this page in a production rollout, pair it with the core operations docs:
- Deployment Mode Matrix for self-hosted, Evaluation, Enterprise, SaaS, and In-VPC fit
- Failure Modes And Recovery for degraded-provider, connector, approval, and runtime behavior
- Capacity Planning for sizing and growth signals
- Community vs Evaluation vs Enterprise for limits, support surfaces, and upgrade triggers
