Common Patterns
Create a workflow, define its graph with PUT /api/workflows/{id}/graph, then execute. For external triggers, deploy the workflow and arm it to get a webhook URL. Webhooks are single-use — re-arm after each trigger. Use the streaming endpoint for real-time block execution updates.CRUD
GET /api/workflows
List workflows.Max results
Pagination offset
POST /api/workflows
Create a workflow.GET /api/workflows/
Get workflow with blocks and edges.Workflow ID
PATCH /api/workflows/
Update workflow metadata.Workflow ID
DELETE /api/workflows/
Delete a workflow.Workflow ID
Graph
PUT /api/workflows//graph
Save the complete graph — blocks and edges.Workflow ID
Deploy
POST /api/workflows//deploy
Deploy the workflow (enables webhook triggering).Workflow ID
POST /api/workflows//undeploy
Undeploy the workflow.Workflow ID
POST /api/workflows//arm
Arm the workflow’s webhook for a single external trigger. Opens a 10-minute window during which the webhook accepts exactly one call; after it fires or expires, re-arm.Workflow ID
The response is
{"ok": true, "armed_until": "<iso8601>"} — not a webhook id/secret. The webhook_id and webhook_secret live on the webhook block’s config in the saved graph; fetch them with GET /api/workflows/{id} and read from the block whose type == "webhook".Execution
POST /api/workflows//execute
Execute the workflow synchronously.Workflow ID
Map of input variable names → values. Defaults to
{} when omitted.variables is the canonical key. The route also accepts input as a legacy alias (data.get("variables", data.get("input", {}))) — prefer variables in new code.POST /api/workflows//execute/stream
Execute with streaming SSE. Same body shape as/execute — pass variables (canonical) or input (legacy alias).
Workflow ID
Map of input variable names → values. Defaults to
{} when omitted.GET /api/workflows//executions
List execution history.Workflow ID
GET /api/workflows//executions//logs
Get per-block execution logs.Workflow ID
Execution ID
Error Responses
Workflow routes return one of two body shapes:- Plain
{"error": "<message>"}— list/create/patch/delete and the deploy/undeploy/arm endpoints. - Structured
{"error": "<message>", "error_code": "<UPPER_SNAKE_CODE>"}(via the sharederror_responsehelper) —GET /workflows/{id},PUT /workflows/{id}/graph, and the synchronous/executeendpoint.
/execute/stream) return HTTP 200 and emit errors as SSE data: {"type": "error", ...} events; only the timeout event includes error_code (EXECUTION_TIMEOUT).
| Status | error_code | Description |
|---|---|---|
| 400 | — | Missing required field (e.g. name, no fields to update, no JSON body) |
| 400 | VALIDATION_ERROR | Graph save: each block needs id/type, each edge needs source/target, block types must be in the engine registry, and edges must reference blocks in the same graph |
| 404 | WORKFLOW_NOT_FOUND | No workflow exists with the given ID (GET /workflows/{id}, PUT /graph, POST /execute) |
| 404 | — | No workflow or execution exists with the given ID (other endpoints) |
| 504 | EXECUTION_TIMEOUT | Synchronous /execute exceeded its timeout |
| 500 | EXECUTION_FAILED | Synchronous /execute raised an error |