Workflows API Reference
All API endpoints require authentication and tenant context unless otherwise noted.
Base URL: /api/v1
Workflows
List Workflows
GET /api/v1/workflows
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status: draft, active, paused, archived |
trigger_type |
string | Filter by trigger: manual, schedule, webhook, event |
search |
string | Search by name or description |
tag |
string | Filter by tag |
sort_by |
string | Sort field (default: created_at) |
sort_dir |
string | Sort direction: asc, desc (default: desc) |
per_page |
integer | Items per page (default: 15) |
all |
boolean | Return all without pagination |
Response:
{
"success": true,
"data": [
{
"id": "uuid",
"name": "Order Confirmation",
"description": "Send confirmation email when order is created",
"status": "active",
"trigger_type": "event",
"trigger_config": {},
"settings": {},
"tags": ["orders", "email"],
"execution_count": 150,
"success_count": 145,
"failure_count": 5,
"last_executed_at": "2025-01-16T10:00:00Z",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-15T00:00:00Z",
"nodes": [...],
"connections": [...]
}
],
"meta": {
"current_page": 1,
"last_page": 5,
"per_page": 15,
"total": 72
}
}
Create Workflow
POST /api/v1/workflows
Request Body:
{
"name": "Order Confirmation",
"description": "Send confirmation email when order is created",
"status": "draft",
"trigger_type": "event",
"trigger_config": {
"event": "order.created"
},
"settings": {
"retry_on_failure": true
},
"tags": ["orders", "email"],
"nodes": [
{
"node_type": "orders:order-created",
"node_category": "trigger",
"label": "Order Created",
"config": {},
"position": { "x": 100, "y": 100 }
},
{
"node_type": "workflows:send-email",
"node_category": "action",
"label": "Send Confirmation",
"config": {
"to": "{{customer.email}}",
"subject": "Order {{order.id}} Confirmed",
"body": "Thank you for your order!"
},
"position": { "x": 100, "y": 250 }
}
],
"connections": [
{
"source_node_index": 0,
"target_node_index": 1
}
]
}
Response:
{
"success": true,
"message": "Workflow created successfully",
"data": {
"id": "uuid",
"name": "Order Confirmation",
...
}
}
Get Workflow
GET /api/v1/workflows/{id}
Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "Order Confirmation",
"description": "...",
"status": "active",
"trigger_type": "event",
"nodes": [
{
"id": "node-uuid",
"workflow_id": "uuid",
"node_type": "orders:order-created",
"node_category": "trigger",
"label": "Order Created",
"config": {},
"position": { "x": 100, "y": 100 },
"is_entry_point": true,
"retry_count": 0,
"retry_delay_seconds": 0,
"timeout_seconds": 0
}
],
"connections": [
{
"id": "conn-uuid",
"workflow_id": "uuid",
"source_node_id": "node-1-uuid",
"target_node_id": "node-2-uuid",
"source_handle": "output",
"target_handle": "input",
"condition_path": null
}
]
}
}
Update Workflow
PUT /api/v1/workflows/{id}
Request Body:
{
"name": "Updated Name",
"description": "Updated description",
"status": "active",
"nodes": [...],
"connections": [...]
}
Response:
{
"success": true,
"message": "Workflow updated successfully",
"data": { ... }
}
Delete Workflow
DELETE /api/v1/workflows/{id}
Response:
{
"success": true,
"message": "Workflow deleted successfully"
}
Activate Workflow
POST /api/v1/workflows/{id}/activate
Validates and activates a workflow. Returns validation errors if invalid.
Response (Success):
{
"success": true,
"message": "Workflow activated successfully",
"data": { ... }
}
Response (Validation Failed):
{
"success": false,
"message": "Workflow validation failed",
"errors": [
"Workflow must have at least one trigger node",
"Node 'Send Email' has no incoming connection"
]
}
Deactivate Workflow
POST /api/v1/workflows/{id}/deactivate
Pauses a workflow, preventing automatic execution.
Response:
{
"success": true,
"message": "Workflow paused successfully",
"data": { ... }
}
Duplicate Workflow
POST /api/v1/workflows/{id}/duplicate
Request Body:
{
"name": "Order Confirmation (Copy)"
}
Response:
{
"success": true,
"message": "Workflow duplicated successfully",
"data": {
"id": "new-uuid",
"name": "Order Confirmation (Copy)",
"status": "draft",
...
}
}
Execute Workflow
POST /api/v1/workflows/{id}/execute
Manually triggers workflow execution.
Request Body:
{
"data": {
"order_id": "123",
"customer_email": "john@example.com"
}
}
Response:
{
"success": true,
"message": "Workflow execution started",
"data": {
"execution_id": "exec-uuid",
"status": "pending"
}
}
Test Run Workflow
POST /api/v1/workflows/{id}/test
Executes workflow in test mode. Validates first.
Request Body:
{
"data": {
"sample": "data"
}
}
Response:
{
"success": true,
"message": "Test run completed",
"data": {
"execution_id": "exec-uuid",
"status": "completed",
"result": { ... }
}
}
Validate Workflow
GET /api/v1/workflows/{id}/validate
Response:
{
"success": true,
"valid": true,
"errors": []
}
Or with errors:
{
"success": false,
"valid": false,
"errors": [
"Workflow must have at least one trigger node",
"Node 'HTTP Request' is missing required config: url"
]
}
Export Workflow
GET /api/v1/workflows/{id}/export
Response:
{
"success": true,
"data": {
"name": "Order Confirmation",
"description": "...",
"trigger_type": "event",
"nodes": [...],
"connections": [...],
"exported_at": "2025-01-16T10:00:00Z",
"version": "1.0"
}
}
Import Workflow
POST /api/v1/workflows/import
Request Body:
{
"workflow": {
"name": "Imported Workflow",
"nodes": [...],
"connections": [...]
}
}
Response:
{
"success": true,
"message": "Workflow imported successfully",
"data": { ... }
}
Get Statistics
GET /api/v1/workflows/stats
Response:
{
"success": true,
"data": {
"total_workflows": 25,
"active_workflows": 18,
"paused_workflows": 5,
"draft_workflows": 2,
"executions_today": 150,
"executions_this_week": 1050,
"executions_this_month": 4200,
"success_rate": 96.5,
"average_duration_ms": 2340,
"most_executed": [
{ "id": "uuid", "name": "Order Confirmation", "count": 500 }
],
"recent_failures": [
{ "id": "exec-uuid", "workflow_name": "...", "error": "..." }
]
}
}
Workflow Nodes (Registry)
List All Nodes
GET /api/v1/workflow-nodes
Response:
{
"success": true,
"data": [
{
"identifier": "workflows:manual-trigger",
"name": "Manual Trigger",
"category": "trigger",
"description": "Start workflow manually",
"icon": "Play",
"color": "#22C55E",
"module": "workflows",
"inputs": [],
"outputs": [
{ "name": "output", "label": "Output", "type": "any" }
],
"configSchema": { ... },
"defaultConfig": { ... }
},
...
]
}
Get Nodes Grouped by Category
GET /api/v1/workflow-nodes/grouped
Response:
{
"success": true,
"data": [
{
"category": "trigger",
"label": "Triggers",
"icon": "Zap",
"color": "#22C55E",
"description": "Start your workflow with these events",
"nodes": [
{ "identifier": "workflows:manual-trigger", ... },
{ "identifier": "workflows:schedule-trigger", ... },
{ "identifier": "orders:order-created", ... }
]
},
{
"category": "action",
"label": "Actions",
"icon": "Play",
"color": "#3B82F6",
"nodes": [...]
}
]
}
Get Categories
GET /api/v1/workflow-nodes/categories
Response:
{
"success": true,
"data": {
"trigger": {
"label": "Triggers",
"icon": "Zap",
"color": "#22C55E",
"description": "Start your workflow with these events"
},
"action": { ... },
"condition": { ... },
"transformer": { ... }
}
}
Get Single Node
GET /api/v1/workflow-nodes/{identifier}
Example: GET /api/v1/workflow-nodes/workflows:send-email
Response:
{
"success": true,
"data": {
"identifier": "workflows:send-email",
"name": "Send Email",
"category": "action",
"description": "Send an email to recipients",
"icon": "Mail",
"color": "#3B82F6",
"module": "workflows",
"inputs": [
{ "name": "input", "label": "Input", "type": "any", "required": true }
],
"outputs": [
{ "name": "output", "label": "Output", "type": "object" }
],
"configSchema": {
"type": "object",
"properties": {
"to": { "type": "string", "title": "To" },
"subject": { "type": "string", "title": "Subject" },
"body": { "type": "string", "title": "Body", "format": "textarea" },
"bodyType": { "type": "string", "enum": ["text", "html"] }
},
"required": ["to", "subject", "body"]
},
"defaultConfig": {
"bodyType": "text"
}
}
}
Validate Node Config
POST /api/v1/workflow-nodes/{identifier}/validate
Request Body:
{
"config": {
"to": "{{customer.email}}",
"subject": "Order Confirmation"
}
}
Response:
{
"success": false,
"valid": false,
"errors": [
"Body is required"
]
}
Check Node Connection
POST /api/v1/workflow-nodes/can-connect
Request Body:
{
"source": "workflows:send-email",
"target": "workflows:if-else"
}
Response:
{
"success": true,
"can_connect": true
}
Simulate a Workflow
POST /api/v1/workflows/{id}/simulate
Walks the workflow and reports what would happen. Nothing is persisted and no
step with real-world effects is run — distinct from POST /workflows/{id}/test,
which executes for real and does send the email.
Body
{ "data": { "order_id": 42 } }
data is the sample payload the trigger would supply. Optional.
Response — 200 when the workflow could run, 422 when it could not.
{
"success": true,
"data": {
"ok": true,
"errors": [],
"warnings": ["Call: URL is required."],
"steps": [
{
"index": 1,
"label": "Start",
"node_type": "workflows:manual-trigger",
"input": { "order_id": 42 },
"config": {},
"mode": "executed",
"reason": null
},
{
"index": 2,
"label": "Email",
"node_type": "workflows:send-email",
"mode": "stubbed",
"reason": "Not run — this step has real-world effects."
}
],
"unreached": ["Stranded"],
"variables": { "greeting": "hello" },
"executed": 1,
"stubbed": 1
}
}
unreached lists nodes the run would never arrive at — usually something left
unconnected on the canvas.
Executions
List Executions
GET /api/v1/workflow-executions
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
workflow_id |
uuid | Filter by workflow |
status |
string | Filter by status |
trigger_type |
string | Filter by trigger type |
from |
date | From date |
to |
date | To date |
per_page |
integer | Items per page |
Response:
{
"success": true,
"data": [
{
"id": "exec-uuid",
"workflow_id": "uuid",
"workflow_name": "Order Confirmation",
"status": "completed",
"trigger_type": "event",
"trigger_data": { ... },
"triggered_by": "user-uuid",
"result": { ... },
"error_message": null,
"nodes_total": 5,
"nodes_executed": 5,
"nodes_failed": 0,
"started_at": "2025-01-16T10:00:00Z",
"completed_at": "2025-01-16T10:00:02Z",
"duration_ms": 2340
}
],
"meta": { ... }
}
Get Workflow Executions
GET /api/v1/workflows/{workflow}/executions
Returns executions for a specific workflow.
Get Execution Detail
GET /api/v1/workflow-executions/{execution}
Response:
{
"success": true,
"data": {
"id": "exec-uuid",
"workflow": { ... },
"status": "completed",
"trigger_type": "manual",
"trigger_data": { "order_id": "123" },
"context": {
"variables": { "discount": 10 }
},
"result": { ... },
"nodes_total": 5,
"nodes_executed": 5,
"started_at": "...",
"completed_at": "...",
"resume_at": null,
"logs": [
{
"id": "log-uuid",
"node_id": "node-uuid",
"node_type": "workflows:manual-trigger",
"node_label": "Manual Trigger",
"status": "completed",
"input_data": { ... },
"output_data": { ... },
"started_at": "...",
"completed_at": "...",
"duration_ms": 5
}
]
}
}
resume_at is set only while a run is suspended waiting out a Delay node or a
retry backoff — it is when the sweeper may wake it. A run an operator paused has
resume_at: null and stays put until it is explicitly re-dispatched.
The scheduler snapshot backing a suspended run is internal and is not serialized on any endpoint.
Get Execution Logs
GET /api/v1/workflow-executions/{execution}/logs
Response:
{
"success": true,
"data": [
{
"id": "log-uuid",
"node_id": "node-uuid",
"node_type": "workflows:send-email",
"node_label": "Send Confirmation",
"status": "completed",
"input_data": {
"order_id": "123",
"customer_email": "john@example.com"
},
"output_data": {
"order_id": "123",
"customer_email": "john@example.com",
"_email_sent": true,
"_sent_at": "2025-01-16T10:00:01Z"
},
"error_message": null,
"retry_attempt": 0,
"started_at": "2025-01-16T10:00:00.500Z",
"completed_at": "2025-01-16T10:00:01.234Z",
"duration_ms": 734
}
]
}
Cancel Execution
POST /api/v1/workflow-executions/{execution}/cancel
Only works for pending or running executions.
Response:
{
"success": true,
"message": "Execution cancelled"
}
Pause Execution
POST /api/v1/workflow-executions/{execution}/pause
Asks a running execution to suspend itself. The worker is not interrupted — it finishes the node it is on, saves a checkpoint and stops there, so this returns before the run has come to rest.
The execution keeps its position and no due time is set, so it stays paused
until re-dispatched. Returns 400 if the execution has already finished or is
already paused.
Response:
{
"success": true,
"message": "Execution will pause once the current step finishes"
}
Retry Execution
POST /api/v1/workflow-executions/{execution}/retry
Creates a new execution with the same trigger data.
Response:
{
"success": true,
"message": "Execution retry started",
"data": {
"execution_id": "new-exec-uuid"
}
}
Webhooks
Get Webhook URL
GET /api/v1/workflows/{workflow}/webhook-url
Response:
{
"success": true,
"data": {
"url": "https://your-domain.com/api/webhooks/workflows/abc123token",
"method": "POST",
"token": "abc123token"
}
}
Trigger Webhook (Public)
POST /api/webhooks/workflows/{token}
No authentication required - uses token for identification.
Request Body:
{
"event": "order.created",
"data": {
"order_id": "123"
}
}
Headers (if signature required):
X-Webhook-Signature: sha256=abc123...
Response:
{
"success": true,
"message": "Workflow triggered",
"data": {
"execution_id": "exec-uuid"
}
}
Error Responses
All endpoints may return these error responses:
400 Bad Request
{
"success": false,
"message": "Invalid request",
"errors": { ... }
}
401 Unauthorized
{
"success": false,
"message": "Unauthenticated"
}
403 Forbidden
{
"success": false,
"message": "Insufficient permissions"
}
404 Not Found
{
"success": false,
"message": "Workflow not found"
}
422 Validation Failed
{
"success": false,
"message": "Validation failed",
"errors": {
"name": ["The name field is required"]
}
}
500 Server Error
{
"success": false,
"message": "An error occurred",
"error": "Error details (in debug mode)"
}
Rate Limiting
API endpoints are rate limited:
- Standard endpoints: 60 requests/minute
- Webhook endpoints: 120 requests/minute
- Execute endpoints: 30 requests/minute
Rate limit headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705398000
Next Steps
- Execution Engine - How execution works
- Extending Workflows - Create custom endpoints
- Examples - API usage examples