Workflows
A workflow is a saved, versioned graph of steps: a trigger, then models, agents, knowledge searches, HTTP calls, integrations, branches, loops, waits, approvals and outputs, joined by edges and passing data with {{ }} bindings. Build it on the canvas in the panel (Workflows), test it in place, publish a version, and run it by hand, on a schedule, from a webhook, from your own app, or as a tool an agent can call.
#Triggers
Every workflow has exactly one trigger. Change its type from the trigger node's inspector.
- Manual — the Test panel's Run button. Its sample input is used when you don't type one.
- API —
POST /v1/workflows/{id-or-name}/runswith a gateway key (scopeworkflows.run). The workflow's API callable switch must be on; without it the call is refused with403 workflow_not_callable, andGET /v1/workflowslists only callable, enabled, valid workflows. Runs are asynchronous (202+ run id) unless you pass?wait=true. An optional input schema checks required keys and primitive types. - Webhook — a URL of the form
/v1/workflows/hooks/{token}. Generate it in the workflow settings; the token is the credential, so regenerate it if it leaks. Pick the accepted method (POST by default, or any).trigger.inputis{ method, query, headers, body }with credential headers removed. Optionally verify an HMAC-SHA256 signature of the body with a Signing secret credential. Respond immediately (202+ run id), with the run's output when it finishes, or from a Respond to webhook node; the two waiting modes give up afterGateway:Workflows:MaxSyncWaitSeconds(60) and return202with the run id. See the Workflows API for limits and status codes. - Schedule — a 5-field cron in UTC. Saving an enabled, valid workflow arms it.
- Error — the entry point of an error workflow: another workflow's settings name this one, and each failed production run starts it with
{ workflow, run, error }.
The same API callable switch also exposes the workflow as an OpenAI-compatible chat model at /v1/workflows/{id-or-name}/chat/completions.
#Data and bindings
Each node's output is available downstream as {{ nodes.<id>.output.<path> }}. Other roots: trigger.input, vars (written by Set variables), env (workspace variables), run (id, workflowName, testMode, resumeUrl…), and loop (item, index, first, last, count — inside a loop only). A value that is only a binding keeps its JSON type, so "{{ nodes.search.output.hits }}" passes a real array.
Type {{ in any field to autocomplete the paths that node may read. The Data tab of a node shows what flowed in and out on the last run; drag a key onto a field to insert its binding, or click it to copy.
Bindings are strict by default: a path that resolves to nothing fails the step (unresolved_binding) instead of sending the literal text to a model. Strictness can be turned off for a whole workflow in its settings or for a single node. The compiler also rejects a binding to a node that isn't guaranteed to run first.
#Node catalogue
- Model — LLM call, Library prompt, Agent (runs a stored agent as one step; it refuses private, dataset and connector agents, since a run has no acting end user or API key to check them against), Classify (labels become output ports, plus
otherfor text matching no label), Extract data (named, typed fields as JSON — type a field by ending its description with(number),(boolean),(array)or(object); works on every provider). - Knowledge & tools — Knowledge search, MCP tool, HTTP request, SQL query (SQL Server, parameterised,
maxRows500, run inside a transaction that is rolled back unless Allow writes is on). - Integrations — Slack, Teams, Outlook send mail, Microsoft Graph request, SharePoint list items / add item, Jira, ServiceNow, GitHub. Each is an HTTP request underneath, with every HTTP guard.
- Logic — Branch, Switch, Loop over items, Merge (by node, append, join on a key, or first to arrive), Wait, Run workflow (wait for the child, or fire-and-forget), Stop (as
completedorfailed). - Data — Set variables, Transform (a structured list of operations: map, filter, groupBy, sum, regexExtract, dateAdd, hash and ~40 more), Parse (JSON, CSV, XML, HTML → text).
- Guardrails — Redact PII, Moderate, Approval.
- Output — Return, Respond to webhook, Webhook, Send email.
#Loops
Everything connected after a Loop over items node's each port is its body and runs once per item; done continues once with results — one entry per item. Iterations can run in parallel (concurrency), items can be batched (batchSize), and continueOnItemError keeps a loop going past a failed item. A body may only be entered through each; the graph stays acyclic. Iterations count towards the run's step budget, and at most Gateway:Workflows:MaxLoggedIterations (50) are kept as individual rows in the waterfall.
#Waiting, approvals and sub-workflows
- Wait pauses for a duration, until a time, or until
{{ run.resumeUrl }}is called. Anything longer thanGateway:Workflows:MaxInlineWaitSeconds(60) suspends the run durably, so it survives restarts. A Wait inside a loop body must stay within that limit (wait_in_loopotherwise). - Approval suspends the run until someone decides in Workflows → Approvals (or via
POST /v1/workflows/runs/{id}/approve|reject), then takes theapprovedorrejectedport. An optional Teams/Slack webhook is notified, and a timeout auto-rejects. - Run workflow runs another workflow as one step and returns its output. Depth is capped (
Gateway:Workflows:MaxDepth, 3) and recursion up the chain is refused.
#Limits and error handling
Each workflow's settings carry its own guard rails: a run timeout (300 s), a step budget (200, loop iterations included), a model-call budget (25), an optional per-run cost ceiling, node concurrency (4), a default error mode and an error workflow, and step retention days (default Gateway:Workflows:StepRetentionDays, 30). Each node can set its own timeout and retry (attempts and backoff), and its onError: fail the run, continue (mark the node failed and skip what depends on it), or route down the node's error port. Engine-wide ceilings under Gateway:Workflows:* — nodes per workflow, depth, iterations, state size, HTTP response size and timeout — can be tightened per workflow but never exceeded; see the Configuration reference.
#Testing
The Test panel runs the draft as a test run:
- Dry run echoes prompts and describes HTTP calls instead of making them. Approvals take the
approvedport without waiting. Because upstream outputs are placeholders, a binding that doesn't resolve becomes empty instead of failing the step; the step's input lists those paths under_dryRunUnresolved, so check it for typos. To exercise the real flow without model spend, pin the model nodes' output and turn dry run off. - Pinned data (a node's Data tab → Pin this output) replaces that node's execution in test runs only. Published, API, schedule and webhook runs never use it.
- Run node executes just the selected node, reusing upstream results from the last run. Run to here executes everything up to it.
- Workspace variables resolve to their test value when one is set.
From a run's page: Retry replays the same graph and input, Retry from here reuses everything upstream of a node, and Debug in editor opens that run's data in the editor.
#Credentials and variables
Workflows → Credentials & variables. Credentials (bearer, API-key header, basic, query parameter, OAuth2 client credentials, SQL Server login, signing secret) are encrypted with Encryption:MasterKey and never returned to the browser. Each HTTP-style credential lists the hosts it may be sent to, and the gateway refuses to attach it anywhere else. Variables are plain values read as {{ env.NAME }} — not for secrets, since resolved values appear in step inputs.
#Outbound access
Nothing leaves the gateway unless an operator allows it:
Gateway:Workflows:Http:AllowedHosts— hosts HTTP, integration and webhook nodes may reach. Empty disables them. Private, loopback and link-local addresses are refused even when allow-listed, checked again at connect time, and redirects are not followed.Gateway:Workflows:Sql:AllowedHosts— SQL servers the SQL node may connect to.Gateway:Workflows:Email:AllowedDomains— recipient domains for Send email. SMTP settings come fromGateway:Workflows:Email:*, falling back toGateway:HealthProbe:Smtp:*.
#Workflows as agent tools
An agent can attach enabled, valid workflows from its own workspace as tools. The tool is named workflow_ plus a slug of the workflow's name, takes the API trigger's input schema as its parameters (or a free-form object), and carries the workflow's description. When the model calls it, Relay runs the workflow inline as a child run — with its own steps and cost nested under the agent's trace — and hands the output back as the tool result; a failure comes back as [tool error] … text the model can react to. The depth cap and recursion refusal apply; the workflow does not need API callable on. A name clash with another attached tool fails the run with 409 tool_name_conflict.
#Versions, access and portability
Snapshot and publish versions from Versions, or click Publish in the editor's top bar to save, snapshot and publish the current draft in one step; production channels run the published version (or the draft when none is published). A workflow can be restricted so only its owner and chosen editors can change or run it. Export and import a workflow as JSON (pin data and webhook tokens are never exported), start from a template, or move many at once through the portability bundle.