Skip to main content

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)

Generated API reference

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.

MethodPathPurposeReference
POST/api/v1/workflows/executeExecute a workflow definitionexecuteWorkflow
GET/api/v1/workflows/executionsList recent workflow executionslistWorkflowExecutions
GET/api/v1/workflows/executions/{id}Get one workflow executiongetWorkflowExecution
GET/api/v1/workflows/executions/tenant/{tenant_id}List executions for a tenantgetTenantWorkflowExecutions
POST/api/v1/planSubmit a query for multi-agent planningexecutePlan
GET/api/v1/plan/{id}Get plan statusgetPlanStatus
GET/api/v1/unified/executions/{id}/streamStream execution status via SSEstreamExecutionStatus

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) header
  • Content-Type: application/json header (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/plan and /api/v1/plan/execute — a missing/zero user.id is rejected with 401.
  • user.email — User email
  • user.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:

FieldTypeRequiredDescription
workflow.metadata.namestringYesWorkflow name (400 if missing)
workflow.spec.stepsarrayYesArray of workflow steps (400 if empty)
inputobjectNoInput data for the workflow
userobjectNoUser 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:

TypeDescription
llm-callSend prompt to an LLM provider (provider, model, max_tokens optional)
connector-callExecute a query or command via an MCP connector (connector, operationquery or executestatement, parameters)
api-callInvoke a registered external API step
conditionalBranch on a condition with if_true / if_false step lists
function-callInvoke 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",
"user_context": { "id": 123, "email": "[email protected]", "role": "user" }
}

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:

StatusMeaning
202Execution paused for human approval (HITL-enabled deployments). Body is the execution object extended with approval_id, approval_status, paused_at_step, and paused_reason.
400Invalid body, missing workflow name, or empty steps array
500Workflow 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:

ParameterTypeDefaultDescription
limitinteger10Number 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).

FieldTypeRequiredDescription
querystringYesNatural language query (400 if missing)
domainstringNoDomain hint: travel, healthcare, finance, generic (default). May also be supplied as context.domain.
execution_modestringNoauto (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.
userobjectYesUser context — user.id must be a non-zero integer (401 otherwise)
clientobjectNoClient info for audit (id, name); org_id / tenant_id are overwritten from the gateway identity headers
contextobjectNoAdditional 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:

StatusMeaning
400Invalid body, missing query, or invalid execution_mode
401Missing user authentication (user.id zero/absent)
500Planning failed or plan storage failed
503Planning 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:

StatusMeaning
400Invalid body or missing context.plan_id
401Missing user authentication (user.id zero/absent)
403Blocked by policy (body is a PlanResponse with success: false and policy_info), or confirm/step mode requested on a non-Enterprise deployment
404Plan not found (or owned by another organization)
409Plan already executed, or plan was cancelled
410Plan expired before execution
429CONCURRENT_EXECUTION_LIMIT — tier-based concurrent execution cap reached (body uses the {"error": {"code", "message"}} format)
500Execution failed
503Workflow 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:

FieldTypeRequiredDescription
versionintegerYesThe plan version you read (optimistic-lock check)
execution_modestringNoNew execution mode (validated against the deployment tier)
domainstringNoNew domain
metadataobjectNoReplacement 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_by": "[email protected]",
"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):

FieldTypeDescription
approved_bystringApprover identity; falls back to the X-User-ID header, then "system"
commentstringAudit 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_by": "[email protected]",
"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:

ParameterTypeDefaultDescription
plan_idstring(all)Filter to a single plan
limitinteger20Result 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:

FieldTypeRequiredDescription
stepsarrayYesWorkflow steps to estimate (400 if empty)
providerstringNoDefault provider applied to steps that don't set one
modelstringNoDefault 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).

note

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:

ParameterTypeDescription
limitintegerMax 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.
offsetintegerPagination offset (default: 0). Invalid values fall back to default.
execution_typestringFilter by type: map_plan or wcp_workflow
statusstringFilter by status (see Execution Status Values)

Headers:

HeaderRequiredDescription
X-Tenant-ID (set by the gateway)NoFilter by tenant ID (multi-tenancy)
X-Org-ID (set by the gateway)NoFilter 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_ or wcp_)
  • 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:

FieldTypeOmitted when empty
execution_idstringNo
execution_typestringNo
namestringNo
sourcestringYes
statusstringNo
current_step_indexintegerNo
total_stepsintegerNo
progress_percentfloatNo
started_atdatetimeNo
completed_atdatetimeYes
durationstringYes
stepsarrayYes
errorstringYes
tenant_idstringYes
org_idstringYes
user_idstringYes
client_idstringYes
estimated_cost_usdfloatYes
actual_cost_usdfloatYes
metadataobjectYes
created_atdatetimeNo
updated_atdatetimeNo

StepStatus field reference:

FieldTypeOmitted when empty
step_idstringNo
step_indexintegerNo
step_namestringNo
step_typestringNo
statusstringNo
started_atdatetimeYes
ended_atdatetimeYes
durationstringYes
decisionstringYes
decision_reasonstringYes
policies_matchedstring[]Yes
approval_statusstringYes
approved_bystringYes
approved_atdatetimeYes
rejected_bystringYes
rejected_atdatetimeYes
modelstringYes
providerstringYes
cost_usdfloatYes
tokens_inintegerYes
tokens_outintegerYes
inputobjectYes
outputobjectYes
result_summarystringYes
errorstringYes

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:

ParameterTypeDescription
idstringExecution ID, WCP workflow ID, or MAP plan ID

Headers:

HeaderRequiredDescription
AuthorizationYesBasic base64(clientId:clientSecret)
X-Tenant-ID, X-Org-IDYes (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:

EventDescription
statusInitial execution state sent on connect
execution.startedExecution has begun
execution.completedExecution completed successfully (terminal)
execution.failedExecution failed (terminal)
execution.cancelledExecution was cancelled (terminal)
step.startedA step has started executing
step.completedA step completed successfully
step.failedA step failed
step.decisionA policy gate decision was made on a step

Connection Lifecycle:

  1. Client connects; server sends the current state as a status event
  2. If the execution is already terminal, the server closes the connection immediately
  3. While running, the server pushes events as execution state changes
  4. A :keepalive SSE comment is sent every 15 seconds to prevent proxy idle timeouts
  5. On terminal event (execution.completed, execution.failed, execution.cancelled), the server closes the connection
  6. 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 StatusError CodeDescription
400BAD_REQUESTMissing execution ID or missing tenant identity
401UNAUTHORIZEDMissing tenant or org identity headers
404NOT_FOUNDExecution not found (or owned by another tenant)
429TOO_MANY_REQUESTSPer-tenant SSE connection limit reached
500INTERNAL_ERRORStreaming not supported or lookup failure
503SERVICE_UNAVAILABLEEvent 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:

FieldTypeRequiredDescription
reasonstringNoReason 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 StatusError CodeDescription
400BAD_REQUESTMissing execution ID or unknown execution type
401UNAUTHORIZEDMissing tenant or org identity headers
404NOT_FOUNDExecution not found (or owned by another tenant)
409CONFLICTExecution already in terminal state
500INTERNAL_ERRORSubsystem cancellation failed

Execution Status Values

Workflow Status

ValueDescription
pendingExecution queued but not started
runningExecution in progress
completedAll steps completed successfully
failedOne or more steps failed
cancelledExecution was cancelled via the cancel endpoint
abortedWCP workflow aborted (e.g., policy violation)
expiredMAP plan expired before execution started

Step Status Values

StatusDescription
pendingStep not yet started
runningStep currently executing
completedStep completed successfully
failedStep failed
skippedStep was skipped
blockedStep blocked by policy (WCP)
approvalStep waiting for human approval (WCP)

Step Types

TypeDescription
llm_callLLM provider invocation
tool_callExternal tool or function call
connector_callMCP connector invocation
human_taskHuman-in-the-loop task
synthesisMAP result synthesis step
actionGeneric action step
gateWCP policy gate evaluation

Execution Flow

  1. An execution starts in running status when submitted
  2. Direct workflow execution runs steps sequentially in array order; MAP plan execution parallelizes according to the plan's execution_mode (auto / parallel / balanced)
  3. If any step fails (and the workflow's soft-failure tolerance, when configured, is exceeded), the execution status becomes failed
  4. On success of all steps, the execution status becomes completed

Gate Decisions

Policy gate decisions on steps (WCP):

DecisionDescription
allowStep allowed to proceed
blockStep blocked by policy
require_approvalStep requires human approval before proceeding

Approval Status

Approval state when a step has decision: "require_approval":

StatusDescription
pendingAwaiting approval
approvedApproved by a user
rejectedRejected by a user
expiredThe 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 StatusError CodeDescription
400BAD_REQUESTMissing or invalid execution ID
401UNAUTHORIZEDMissing tenant or org identity headers
404NOT_FOUNDExecution not found
409CONFLICTExecution already in terminal state (cancel only)
429TOO_MANY_REQUESTS / CONCURRENT_EXECUTION_LIMIT / COST_ESTIMATE_LIMIT_EXCEEDEDTier limit reached
500INTERNAL_ERRORInternal server error
503SERVICE_UNAVAILABLEEvent streaming not available

Next Steps

Operational Readiness Checklist

Before relying on this page in a production rollout, pair it with the core operations docs: