Workflow API
Manage workflows, execute runs, subscribe to execution streams, and trigger via Webhook
Overview
The Workflow API manages the full lifecycle and execution of workflows:
- Manage workflows: List, get, create, update, delete workflows
- Execute workflows: Run published workflows with input parameters
- Query execution status: Get run details and node-level execution info
- List execution history: Paginate through workflow runs
- Cancel execution: Terminate a running execution
- Webhook trigger: Trigger workflows asynchronously via Webhook
- Statistics: Get workflow run statistics and trends
Base URL: /api/v1/workflows
Authentication
Workflow management and user-initiated run/status routes require an authenticated JWT user session; API-key authentication is not accepted by those routes. The webhook trigger is the exception: POST /api/v1/workflows/webhook/{webhook_token} requires a clou_ API key in its Authorization header.
Required scopes:
| Scope | Purpose |
|---|---|
workflow:read | List and view workflows |
workflow:create | Create workflows |
workflow:update | Update workflows |
workflow:delete | Delete workflows |
workflow:run | Execute workflows |
Endpoint Overview
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/workflows | List workflows |
| POST | /api/v1/workflows | Create workflow |
| GET | /api/v1/workflows/{workflow_id} | Get workflow details |
| PUT | /api/v1/workflows/{workflow_id} | Update workflow |
| DELETE | /api/v1/workflows/{workflow_id} | Delete workflow |
| POST | /api/v1/workflows/{workflow_id}/publish | Publish workflow |
| POST | /api/v1/workflows/{workflow_id}/unpublish | Unpublish workflow |
| POST | /api/v1/workflows/{workflow_id}/duplicate | Duplicate workflow |
| POST | /api/v1/workflows/{workflow_id}/regenerate-webhook-token | Regenerate Webhook Token |
| POST | /api/v1/workflows/{workflow_id}/run | Execute a published workflow |
| POST | /api/v1/workflows/{workflow_id}/debug | Debug-run against the current draft |
| GET | /api/v1/workflows/runs | List runs across workflows |
| GET | /api/v1/workflows/runs/stats | Run statistics across workflows |
| GET | /api/v1/workflows/runs/{run_id} | Get execution status |
| DELETE | /api/v1/workflows/runs/{run_id} | Delete a run record |
| GET | /api/v1/workflows/runs/{run_id}/stream | SSE execution event stream |
| GET | /api/v1/workflows/runs/{run_id}/nodes | Node execution details |
| POST | /api/v1/workflows/runs/{run_id}/cancel | Cancel execution |
| GET | /api/v1/workflows/{workflow_id}/runs | List execution history for a workflow |
| GET | /api/v1/workflows/{workflow_id}/runs/mine | Current user's runs for a workflow |
| GET | /api/v1/workflows/{workflow_id}/runs/mine/{run_id} | Current user's run details |
| GET | /api/v1/workflows/{workflow_id}/runs/mine/{run_id}/nodes | Node details for the current user's run |
| GET | /api/v1/workflows/{workflow_id}/runs/{run_id}/pause-request | Get pending pause/approval request |
| POST | /api/v1/workflows/{workflow_id}/runs/{run_id}/pause-requests/{pause_request_id}/submit | Submit approval or variables to resume execution |
| GET | /api/v1/workflows/{workflow_id}/stats | Workflow statistics |
| GET | /api/v1/workflows/{workflow_id}/stats/trends | Trend data |
| GET | /api/v1/workflows/{workflow_id}/versions | Version snapshot list |
| GET | /api/v1/workflows/{workflow_id}/versions/{version} | Version snapshot details |
| POST | /api/v1/workflows/{workflow_id}/versions | Create a version snapshot |
| POST | /api/v1/workflows/{workflow_id}/versions/{version}/restore | Restore a version snapshot |
| POST | /api/v1/workflows/webhook/{webhook_token} | Webhook trigger |
List Workflows
Get all workflows the current user has access to.
Endpoint
GET /api/v1/workflowsQuery Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | integer | No | 1 | Page number |
page_size | integer | No | 20 | Items per page |
team_id | string | No | - | Filter by team ID |
status | string | No | - | Filter by status: draft, published, archived |
trigger_type | string | No | - | Filter by trigger type: manual, cron, webhook |
visibility | string | No | - | Filter by visibility: private, team, public |
keyword | string | No | - | Search by name or description |
own_only | boolean | No | false | Only show workflows created by the current user |
Request Example
curl -X GET "https://your-domain.com/api/v1/workflows?page=1&page_size=20" \
-H "Authorization: Bearer YOUR_TOKEN"Response
Success (200 OK):
{
"code": 0,
"data": {
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Document Summarizer",
"description": "Summarizes documents automatically",
"icon": "📄",
"status": "published",
"visibility": "team",
"trigger_type": "manual",
"run_count": 156,
"success_count": 147,
"fail_count": 9,
"created_by_id": "user-001",
"created_by_name": "alice",
"created_at": "2026-02-11T10:00:00Z",
"updated_at": "2026-02-11T15:30:00Z"
}
],
"total": 42,
"page": 1,
"page_size": 20
},
"msg": "success"
}Get Workflow
Get complete information about a specific workflow, including definition, variables, trigger config, etc.
Endpoint
GET /api/v1/workflows/{workflow_id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_id | string | Yes | Workflow UUID |
Request Example
curl -X GET "https://your-domain.com/api/v1/workflows/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_TOKEN"Response
Success (200 OK):
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"team_id": "team-123",
"name": "Document Summarizer",
"description": "Summarizes documents automatically",
"icon": "📄",
"definition": {
"nodes": [
{
"id": "node-1",
"type": "start",
"position": {"x": 100, "y": 100}
},
{
"id": "node-2",
"type": "http_request",
"config": {
"url": "{{input.document_url}}",
"method": "GET"
},
"position": {"x": 300, "y": 100}
}
],
"edges": [
{
"id": "edge-1",
"source": "node-1",
"target": "node-2"
}
]
},
"variables": [],
"status": "published",
"visibility": "team",
"version": 2,
"trigger_type": "manual",
"trigger_config": {},
"webhook_token": "wh_abc123...",
"embed_config": {},
"run_page_config": {
"presentation_mode": "simple"
},
"run_count": 156,
"success_count": 147,
"fail_count": 9,
"created_by_id": "user-001",
"created_at": "2026-02-11T10:00:00Z",
"updated_at": "2026-02-11T15:30:00Z"
},
"msg": "success"
}Create Workflow
Create a new workflow. Workflow definition and variables are added later via PUT /api/v1/workflows/{workflow_id} and the versions endpoints.
Endpoint
POST /api/v1/workflowsRequest Body
{
"team_id": "team-123",
"name": "Document Summarizer",
"description": "Summarizes documents automatically",
"icon": "📄",
"visibility": "private"
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
team_id | string | Yes | Team UUID |
name | string | Yes | Workflow name (max 100 chars) |
description | string | No | Workflow description |
icon | string | No | Icon |
visibility | string | No | private, team, or public (default: private) |
Workflow definition and variables are added later via PUT /api/v1/workflows/{workflow_id} and the versions endpoints.
Request Example
curl -X POST "https://your-domain.com/api/v1/workflows" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"team_id": "team-123",
"name": "Document Summarizer",
"description": "Summarizes documents automatically",
"visibility": "private"
}'Response
Success (200 OK):
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"team_id": "team-123",
"name": "Document Summarizer",
"description": "Summarizes documents automatically",
"icon": null,
"definition": {
"nodes": [{"id": "user_input-1", "type": "user_input"}],
"edges": [],
"viewport": {"x": 0, "y": 0, "zoom": 1}
},
"variables": [],
"status": "draft",
"visibility": "private",
"version": 1,
"trigger_type": "manual",
"trigger_config": {},
"webhook_token": null,
"embed_config": {},
"run_page_config": {
"presentation_mode": "simple"
},
"run_count": 0,
"success_count": 0,
"fail_count": 0,
"created_by_id": "user-001",
"created_at": "2026-02-11T10:00:00Z",
"updated_at": "2026-02-11T10:00:00Z"
},
"msg": "Workflow created successfully"
}Update Workflow
Update an existing workflow. All fields are optional; only include fields you want to update.
Endpoint
PUT /api/v1/workflows/{workflow_id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_id | string | Yes | Workflow UUID |
Request Body
{
"name": "Updated Workflow Name",
"description": "Updated description",
"icon": "📄",
"definition": {},
"variables": [],
"trigger_type": "manual",
"trigger_config": {},
"visibility": "team",
"embed_config": {},
"run_page_config": {
"presentation_mode": "simple"
}
}Request Example
curl -X PUT "https://your-domain.com/api/v1/workflows/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Workflow Name",
"description": "Updated description"
}'Response
Success (200 OK):
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Updated Workflow Name",
"description": "Updated description",
"status": "draft",
"visibility": "private",
"version": 2,
"trigger_type": "manual",
"updated_at": "2026-02-11T16:00:00Z"
},
"msg": "Workflow updated successfully"
}Delete Workflow
Permanently delete a workflow.
Endpoint
DELETE /api/v1/workflows/{workflow_id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_id | string | Yes | Workflow UUID |
Request Example
curl -X DELETE "https://your-domain.com/api/v1/workflows/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_TOKEN"Response
Success (200 OK):
{
"code": 0,
"data": null,
"msg": "Workflow deleted successfully"
}Execute Workflow
Run a workflow with input parameters. Execution is always asynchronous: the run is submitted to Celery and the endpoint returns immediately with the run ID and stream URL. The workflow must be published (status: published) before it can be run.
Endpoint
POST /api/v1/workflows/{workflow_id}/runPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_id | string | Yes | Workflow UUID |
Request Body
{
"inputs": {
"document_url": "https://example.com/document.pdf",
"summary_length": "short"
}
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
inputs | object | No | Input variables for the workflow (default: {}) |
Request Example
curl -X POST "https://your-domain.com/api/v1/workflows/550e8400-e29b-41d4-a716-446655440000/run" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"inputs": {
"document_url": "https://example.com/document.pdf",
"summary_length": "short"
}
}'Response
Success (200 OK):
{
"code": 0,
"data": {
"run_id": "run-789",
"stream_url": "/api/v1/workflows/runs/run-789/stream"
},
"msg": "Workflow execution started"
}Progress is available via GET /api/v1/workflows/runs/{run_id}/stream (SSE, optional from_sequence query parameter) and GET /api/v1/workflows/runs/{run_id}. The SSE stream requires an authenticated user with access to the workflow; a webhook token or stream URL is not a public authorization mechanism.
Publish, Unpublish, and Duplicate
| Endpoint | Purpose |
|---|---|
POST /api/v1/workflows/{workflow_id}/publish | Publish the workflow: status becomes published and a webhook_token is assigned/kept |
POST /api/v1/workflows/{workflow_id}/unpublish | Unpublish: status returns to draft |
POST /api/v1/workflows/{workflow_id}/duplicate | Copy the workflow inside its team, including nodes, edges, configs, and variables |
curl -X POST "https://your-domain.com/api/v1/workflows/550e8400-e29b-41d4-a716-446655440000/publish" \
-H "Authorization: Bearer YOUR_TOKEN"- Publish/unpublish return the updated
WorkflowOut. - Duplicate returns the new
WorkflowOutindraftstatus withrun_count/success_count/fail_countreset to zero. - Only a workflow with
status: publishedcan be executed viaPOST /{workflow_id}/run; otherwise the call returns403withworkflow_not_published.
Debug Run
POST /api/v1/workflows/{workflow_id}/debugRuns the workflow using its current draft definition (no publish required). The body is the same as run ({"inputs": {...}}) and it requires workflow:run plus write access to the workflow. The created run has is_debug: true and can be filtered with is_debug=true in run lists.
Response (200 OK):
{
"code": 0,
"data": {
"run_id": "run-790",
"stream_url": "/api/v1/workflows/runs/run-790/stream"
},
"msg": "Workflow execution started"
}Delete a Run
DELETE /api/v1/workflows/runs/{run_id}Deletes a run record (along with its node executions). On success data is {"id": "<run_id>"}.
Get Execution Status
Check the status of a workflow run.
Endpoint
GET /api/v1/workflows/runs/{run_id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | Run UUID |
Request Example
curl -X GET "https://your-domain.com/api/v1/workflows/runs/run-789" \
-H "Authorization: Bearer YOUR_TOKEN"Response
Success (200 OK):
{
"code": 0,
"data": {
"id": "run-789",
"workflow_id": "550e8400-e29b-41d4-a716-446655440000",
"trigger_type": "manual",
"triggered_by_id": "user-001",
"is_debug": false,
"status": "success",
"inputs": {
"document_url": "https://example.com/document.pdf",
"summary_length": "short"
},
"outputs": {
"summary": "The document discusses...",
"word_count": 1234,
"key_points": ["Point 1", "Point 2", "Point 3"]
},
"parent_run_id": null,
"root_run_id": "run-789",
"depth": 0,
"created_at": "2026-02-11T14:30:00Z",
"started_at": "2026-02-11T14:30:00Z",
"finished_at": "2026-02-11T14:31:23Z",
"total_nodes": 6,
"executed_nodes": 6,
"failed_nodes": 0,
"skipped_nodes": 0,
"total_duration_ms": 83000,
"total_token_usage": {},
"error_message": null,
"error_node_id": null
},
"msg": "success"
}Run status values: pending, running, success, waiting, failed, cancelled, timeout.
A user's own published-workflow runs can also be retrieved via GET /api/v1/workflows/{workflow_id}/runs/mine/{run_id} (requires workflow:run), with node-level detail at GET /api/v1/workflows/{workflow_id}/runs/mine/{run_id}/nodes. Node-level execution detail from the management view is available at GET /api/v1/workflows/runs/{run_id}/nodes.
List Executions
Get execution history for a workflow.
Endpoint
GET /api/v1/workflows/{workflow_id}/runsPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_id | string | Yes | Workflow UUID |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | integer | No | 1 | Page number |
page_size | integer | No | 20 | Items per page (maximum 100) |
status | string | No | - | Filter by status: pending, running, success, waiting, failed, cancelled, timeout |
is_debug | boolean | No | - | Filter by debug runs |
search | string | No | - | Search by run ID (non-UUID values return no results) |
created_after | string | No | - | Only runs created after this time (ISO 8601) |
created_before | string | No | - | Only runs created before this time (ISO 8601) |
Request Example
curl -X GET "https://your-domain.com/api/v1/workflows/550e8400-e29b-41d4-a716-446655440000/runs?page=1&page_size=20&status=success" \
-H "Authorization: Bearer YOUR_TOKEN"Response
Success (200 OK):
{
"code": 0,
"data": {
"items": [
{
"id": "run-789",
"workflow_id": "550e8400-e29b-41d4-a716-446655440000",
"trigger_type": "manual",
"triggered_by_id": "user-001",
"is_debug": false,
"status": "success",
"inputs": {},
"outputs": {},
"parent_run_id": null,
"root_run_id": "run-789",
"depth": 0,
"created_at": "2026-02-11T14:30:00Z",
"started_at": "2026-02-11T14:30:00Z",
"finished_at": "2026-02-11T14:31:23Z",
"total_nodes": 6,
"executed_nodes": 6,
"failed_nodes": 0,
"skipped_nodes": 0,
"total_duration_ms": 83000,
"total_token_usage": {},
"error_message": null,
"error_node_id": null,
"execution_duration_ms": 83000,
"config_snapshot": null,
"model_used": null
}
],
"total": 156,
"page": 1,
"page_size": 20
},
"msg": "success"
}Cancel Execution
Cancel a running workflow execution.
Endpoint
POST /api/v1/workflows/runs/{run_id}/cancelPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | Run UUID |
Request Example
curl -X POST "https://your-domain.com/api/v1/workflows/runs/run-789/cancel" \
-H "Authorization: Bearer YOUR_TOKEN"Response
Success (200 OK):
{
"code": 0,
"data": {
"run_id": "run-789",
"status": "cancelled"
},
"msg": "Workflow execution cancelled"
}Cross-Workflow Runs and Statistics
Beyond per-workflow queries, you can list runs and statistics across every accessible workflow. Both narrow results by each workflow's visibility (YUN-153): another member's PRIVATE workflow is hidden even within the same team, matching the access rules of GET /workflows/{workflow_id}.
List Runs Across Workflows
GET /api/v1/workflows/runs| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
team_id | array | No | - | Filter by team (repeatable, requires team membership) |
workflow_id | array | No | - | Filter by workflow (repeatable) |
status | array | No | - | Filter by status (repeatable) |
trigger_type | array | No | - | Filter by trigger type (repeatable) |
user_id | array | No | - | Filter by triggering user (repeatable) |
is_debug | boolean | No | - | Only debug runs |
search | string | No | - | Search by workflow name |
page | integer | No | 1 | Page number |
page_size | integer | No | 20 | Items per page (max 100) |
Requires workflow:read.
Run Statistics Across Workflows
GET /api/v1/workflows/runs/stats?period=7d| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
team_id | string | No | - | Filter by team |
period | string | No | - | Time range: 7d, 30d |
own_only | boolean | No | false | Only workflows created by the current user |
Returns total_runs, runs_by_status, runs_by_workflow (top 10 workflows by run count), and avg_duration_ms. Requires workflow:read.
Workflow Versions
Integer-numbered version snapshots of a single workflow are managed by this router's /{workflow_id}/versions endpoints; the full version-management API with diff, publish, archive, rollback, and fork lives in the Workflow Versions API under /api/v1/workflow-versions/....
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/workflows/{workflow_id}/versions | List snapshots (newest version first) |
| GET | /api/v1/workflows/{workflow_id}/versions/{version} | Get an integer version snapshot |
| POST | /api/v1/workflows/{workflow_id}/versions | Snapshot the current state |
| POST | /api/v1/workflows/{workflow_id}/versions/{version}/restore | Restore that snapshot |
Webhook Trigger
Trigger a workflow via webhook. The webhook token is in the URL path, and the request must additionally authenticate with an API key via the Authorization header (Bearer clou_...). The workflow must be published and its trigger type must be webhook. The API key must be allowed to access the workflow. The token and stream URL are not public/no-auth access; workflow access is still enforced.
Endpoint
POST /api/v1/workflows/webhook/{webhook_token}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webhook_token | string | Yes | The workflow's webhook token |
Authentication
Authorization: Bearer {api_key}where {api_key} is an API key starting with clou_. The workflow's webhook token itself is not an authentication credential; the API key authenticates the caller, and the token selects the workflow.
Request Body
Raw JSON object of workflow inputs:
{
"document_url": "https://example.com/document.pdf",
"summary_length": "short"
}Request Example
curl -X POST "https://your-domain.com/api/v1/workflows/webhook/wh_abc123" \
-H "Authorization: Bearer clou_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"document_url": "https://example.com/document.pdf",
"summary_length": "short"
}'Response
Success (200 OK):
{
"code": 0,
"data": {
"run_id": "run-789",
"status": "pending",
"stream_url": "/api/v1/workflows/runs/run-789/stream"
},
"msg": "Workflow execution started"
}A new webhook token can be generated with POST /api/v1/workflows/{workflow_id}/regenerate-webhook-token.
Get Workflow Statistics
Get usage statistics for a workflow.
Endpoint
GET /api/v1/workflows/{workflow_id}/statsPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow_id | string | Yes | Workflow UUID |
Request Example
curl -X GET "https://your-domain.com/api/v1/workflows/550e8400-e29b-41d4-a716-446655440000/stats" \
-H "Authorization: Bearer YOUR_TOKEN"Response
Success (200 OK):
{
"code": 0,
"data": {
"total_runs": 156,
"success_count": 147,
"failed_count": 9,
"timeout_count": 0,
"avg_duration_ms": 83000,
"last_run_at": "2026-02-11T14:30:00Z"
},
"msg": "success"
}A trends endpoint is also available: GET /api/v1/workflows/{workflow_id}/stats/trends?period=7d (period defaults to 7d; 7d and 30d are supported; the response contains period and a per-day data array of date, runs, success, failed, avgDuration).
Although {workflow_id}/stats and {workflow_id}/stats/trends only declare workflow:read, the implementation validates write access to the target workflow (require_write=True). Only callers with write access (the creator, or a team member with write permission) can read these two endpoints; read-only shares are rejected.
Error Codes
| Code | Message | Description |
|---|---|---|
4000 | Not found | Workflow or run does not exist |
1004 | Forbidden | Workflow not published / webhook trigger disabled / invalid webhook token |
3000 | Permission denied | Insufficient permissions |
1001 | Validation failed | Invalid request data |
5104 | Duplicate name | Workflow name is taken |
No per-endpoint rate limits are implemented. There is no rate-limit middleware on these endpoints.
Execution Stream
Connect to GET /api/v1/workflows/runs/{run_id}/stream to get SSE execution event stream, including node start, output, skipped, complete, and error events.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from_sequence | integer | No | Continue from a known sequence number, for reconnection after disconnect |
After a disconnect, continue from a known sequence number using from_sequence; do not re-run nodes with external side effects to "compensate" for a disconnect.
Publishing and Scope
The run API Key needs workflow:run, and the target workflow must satisfy team and visibility rules. Drafts can only run through the debug endpoint; public embedded pages render results according to the workflow's publishing configuration.
How is this guide?