What is a Workflow?
A Workflow is a directed acyclic graph (DAG) of blocks connected by edges. Each block performs a specific action — calling an LLM, running code, evaluating a condition, or executing an agent. Data flows from block to block through the edges. Unlike orchestrations (where the coordinator decides what happens), workflows follow a fixed, predetermined path every time.Block Types
The block registry accepts these canonical types (plus the back-compat aliasesfunction for code and api_call for general_api):
| Block | Description | Key Config |
|---|---|---|
| starter | Manual / API trigger — declares the workflow’s input variables | None (variables are passed at execution time) |
| webhook | HTTP trigger — exposes the workflow at POST /api/webhooks/{webhook_id} once deployed/armed | webhook_id (UUID, you mint it via API or the studio mints it for you), webhook_secret |
| agent | Runs an existing agent with a message | agent_id, message (template with {{variables.x}} interpolation) |
| orchestration | Delegates to a multi-agent coordinator | orchestration_id, message |
| code | Executes custom Python or JavaScript | Language, source, input mappings |
| condition | Branches the flow based on a boolean expression | Expression evaluated against upstream outputs |
| split | Parallel fan-out — runs downstream branches concurrently | Branch selection rules |
| platform_api | Calls a platform resource (KB search, agent run, etc.) | Resource type + parameters |
| general_api | Calls an external HTTP API | URL, method, headers, body template |
| response | Returns the workflow result back to the caller | Result template referencing upstream block outputs |
PUT /api/workflows/{id}/graph with 400 Unknown block type.
Graph Execution
When you execute a workflow, the engine evaluates blocks in topological order. Each block receives the outputs of its upstream blocks as input. Condition blocks create branches — only the matching branch continues execution. The workflow finishes when all output blocks have been reached.Programmatic vs Copilot
You can build workflows two ways. The programmatic approach uses the PUT /api/workflows/{id}/graph endpoint to define blocks and edges as JSON. The Copilot approach uses natural language — describe what you want, and the AI copilot generates the workflow graph for you. Both produce the same underlying graph structure.Variables and references
Workflow blocks pass data to downstream blocks through theiroutput. To reference an upstream block’s output from another block’s config, use angle-bracket reference syntax:
<Lookup Customer.output.email> is valid.
Two contexts:
- Inside a string (most block configs): every
<blockId.output.field>placeholder gets substituted as a string."Hello <fetch.output.name>!"becomes"Hello Alice!". - Inside a JSON value (e.g.
general_apibody,codeinputs, agent block messages): if the entire string is one reference, the resolved value is returned with its original type (so you can pass a number, array, or object — not just a string)."<extract.output.tags>"returns["foo", "bar"]rather than'["foo", "bar"]'.
<starter.output.variableName>, and you’ll also see the older {{variables.x}} syntax in agent / code block templates — both work; the angle-bracket form is canonical and applies to every block.
Unresolvable references (block not yet run, missing field) leave the placeholder string as-is so you can see what failed when inspecting block logs.
For condition blocks, the expression evaluator uses a Python-safe AST subset — comparisons, BoolOp (and/or/not), BinOp (+/-/*//), attribute access, and subscripting. Function calls are not permitted.
Scheduling
When a workflow’s starter block hasschedule_enabled: true in its config, deploying the workflow materializes a schedule_config on the workflow row and Celery’s scheduler tick (every 30 seconds) fires runs at the configured cadence.
The starter block’s config takes:
| Field | Type | Notes |
|---|---|---|
schedule_enabled | bool | Must be true for any scheduling to happen |
schedule_type | "interval" | "cron" | Default interval |
schedule_timezone | IANA name | Default UTC |
schedule_start_at / schedule_end_at | ISO 8601 | Optional bounds; runs outside the window are skipped |
schedule_max_runs | int | Optional cap; once reached, the workflow stops being scheduled |
schedule_interval_value | int | For interval type. Minimum effective interval is 60 seconds even if you set a smaller value |
schedule_interval_unit | "minutes" | "hours" | "days" | For interval type. Default minutes |
schedule_cron | cron expression | For cron type. Default 0 * * * * (top of every hour). croniter syntax |
/deploy, the platform reads these from the starter block, normalizes them into schedule_config on the workflow row, resets schedule_run_count to 0, and the tick worker picks it up. /undeploy clears schedule_config and stops further scheduled runs.
Scheduled runs execute as if invoked through /execute — the starter block’s variables get whatever default values are configured (no per-run override is possible from the schedule itself).
Deployment & Webhooks
Workflows expose two activation modes for their webhook block:- Deploy (
POST /api/workflows/{id}/deploy) — setsstate = "deployed". The webhook accepts unlimited calls until youundeploy. Use this for production. - Arm (
POST /api/workflows/{id}/arm) — leavesstate = "internal"but opens a 10-minute window during which the webhook accepts exactly one call. After it fires (or expires), you must arm again. Use this for one-shot tests.
webhook_id and webhook_secret live in the webhook block’s config — they’re stored on the block when you add it to the graph. The studio editor mints both client-side when you drag in a webhook block. Neither /deploy nor /arm returns secrets — /deploy returns {"ok": true, "state": "deployed"} and /arm returns {"ok": true, "armed_until": "<iso8601>"}. To retrieve credentials programmatically, fetch the workflow with GET /api/workflows/{id} and read them from the webhook block’s config.
Next Steps
Workflows (Programmatic)
Build a workflow step by step using the API.
Workflows (Copilot)
Build a workflow using natural language.
Workflows API Reference
Full endpoint documentation.