Variables and step outputs
Use these bindings anywhere QuickFlo accepts a Liquid template. Autocomplete shows the values available at the current step.
Referencing Step Outputs
Section titled “Referencing Step Outputs”Step outputs are referenced by their step ID directly — not nested under a steps prefix:
{{ my-step-id.someOutputField }}For example, if you have a step with ID fetch-users that returns a list of users:
{{ fetch-users.data }}{{ fetch-users.data[0].name }}{{ fetch-users.totalCount }}Step Metadata
Section titled “Step Metadata”Every step exposes a $meta object with execution metadata:
{{ fetch-users.$meta.success }} // boolean — true if the step ran without throwing AND wasn't an error-severity operational failure{{ fetch-users.$meta.skipped }} // boolean — true if the step's skipCondition matched{{ fetch-users.$meta.durationMilliseconds }} // number — execution time in ms{{ fetch-users.$meta.stepType }} // string — step type name{{ fetch-users.$meta.operationalStatus }} // 'ok' | 'warning' | 'error' (see Operational Errors){{ fetch-users.$meta.error }} // object — present when the step *threw* (execution error){{ fetch-users.$meta.operationalErrors }} // array — present when classifyOutput() flagged the result (operational error)$meta.error vs $meta.operationalErrors vs $errors — three different surfaces, three different jobs:
$meta.error(per-step, singular object) — only set when the step’s code threw. Usestep.$meta.error.messageto read the thrown message.$meta.operationalErrors(per-step, array) — only set when the step ran successfully but the result was a failure (HTTP 4xx, SMTP rejection, file not found, LLM rate limit). The original output is still readable. Usestep.$meta.operationalErrors[0].codeand.message.$errors(workflow-global, array) — every error from every step in the run, aggregated. Use it to ask “did anything fail anywhere?” — see Operational Errors below.
For “did this specific step succeed?” use step.$meta.success. It is false for both execution and operational failures. See Warnings and partial results for the practical pattern.
$meta.error is an object, not a string. When present, it has these fields:
| Field | Description |
|---|---|
.message | Human-readable error message |
.name | Error class name (e.g., WorkflowError, Five9Error) |
.code | Optional machine-readable code (e.g., HTTP_CLIENT_ERROR) |
.severity | Optional severity level |
.isRetryable | Optional boolean—true when QuickFlo considers the error temporary |
{{ fetch-users.$meta.error.message }}{{ fetch-users.$meta.error.code }}For operational errors specifically, use $meta.operationalErrors (an array) or the global $errors variable described below.
Template Variables
Section titled “Template Variables”These global variables are available in every template expression:
| Variable | Description |
|---|---|
{{ initial.* }} | Data passed when the workflow execution started |
{{ step-id.* }} | Output from a completed step, referenced by its step ID |
{{ $env.* }} | Environment variables |
{{ $connections.* }} | Connection credential objects |
{{ $vars.* }} | Workflow variables set by set-variable steps |
{{ $util.* }} | Utility generators (UUIDs, timestamps, etc.) |
{{ $execution.* }} | Current execution identity — see Execution Context below |
{{ $errors.* }} | Array of operational and execution errors that have accumulated during the run — see Operational Errors below |
Initial Data
Section titled “Initial Data”The initial object contains the data that triggered the workflow execution. Its structure depends on the trigger type. To define the shape your workflow expects and its defaults, see Initial Data.
Webhook Triggers
Section titled “Webhook Triggers”When a workflow is triggered via webhook, the request body fields are spread to the root of initial, and a webhook context object provides access to the full request:
{{ initial.someFieldFromBody }}{{ initial.webhook.query.page }}{{ initial.webhook.query.filter }}{{ initial.webhook.headers['content-type'] }}{{ initial.webhook.body }}{{ initial.webhook.params }}The webhook object contains:
| Field | Description |
|---|---|
webhook.body | Raw request body |
webhook.query | URL query parameters (?key=value) |
webhook.params | URL path parameters |
webhook.headers | Request headers (lowercase keys) |
webhook.files | Uploaded files (multipart/form-data) with base64 buffers |
For JSON request bodies, all top-level fields are also accessible directly:
// POST body: { "userId": 123, "action": "sync" }{{ initial.userId }} // 123{{ initial.action }} // "sync"{{ initial.webhook.query.debug }} // query param ?debug=trueForm Triggers
Section titled “Form Triggers”Form submissions spread the submitted field values to the root and include a form context:
{{ initial.name }}{{ initial.email }}{{ initial.form.formName }}{{ initial.form.submittedAt }}{{ initial.form.authenticatedUser.username }}The form object contains:
| Field | Description |
|---|---|
form.triggerId | The trigger ID |
form.formName | Name of the form |
form.submittedAt | ISO 8601 timestamp of submission |
form.authenticatedUser | Present if the form requires authentication |
form.authenticatedUser.username | The authenticated user’s username |
form.authenticatedUser.connectionName | The form-auth connection used |
form.authenticatedUser.metadata | Custom metadata from the form-auth connection |
Schedule Triggers
Section titled “Schedule Triggers”Scheduled workflows receive the initialData configured in the trigger settings, spread directly to the root:
// initialData config: { "reportType": "daily", "emailTo": "admin@example.com" }{{ initial.reportType }} // "daily"{{ initial.emailTo }} // "admin@example.com"Event Triggers
Section titled “Event Triggers”Event payloads from connected services are spread directly to the root of initial. The structure depends on the event provider:
{{ initial.eventType }}{{ initial.data.agentId }}{{ initial.data.newState }}Manual Execution
Section titled “Manual Execution”When executing a workflow manually or via API, the provided initial data is spread to the root:
// API call: POST /workflow-templates/:id/execute { "initial": { "name": "John" } }{{ initial.name }} // "John"Workflow Variables ($vars)
Section titled “Workflow Variables ($vars)”The set-variable step writes values into $vars. Each set-variable step merges its output into the existing $vars object, so values persist and accumulate across the workflow:
{{ $vars.customerName }}{{ $vars.retryCount | default: 0 }}Connections ($connections)
Section titled “Connections ($connections)”Reference connection credential objects by their connection name:
{{ $connections.my-salesforce }}{{ $connections.my-crm.accessToken }}See Connections for setup guides.
Environment Variables ($env)
Section titled “Environment Variables ($env)”Reference encrypted environment variables. Variables from the workflow’s default environment are available at the root level:
{{ $env.API_KEY }}{{ $env.DATABASE_URL }}Variables from other environments are scoped by environment name:
{{ $env.staging.API_KEY }}See Environments for details on setup and connection redirection.
Execution Context ($execution)
Section titled “Execution Context ($execution)”$execution exposes the current run’s identity — useful for stamping side-effects (claimed rows, log lines, external API metadata) so they correlate back to a specific execution in traces or external systems.
| Field | Type | Description |
|---|---|---|
$execution.id | string | Unique execution ID (UUID) for the current run |
$execution.workflowId | string | ID of the workflow being executed (empty for ad-hoc / unsaved runs) |
$execution.workflowName | string | Human-readable workflow name |
$execution.organizationId | string | Organization running this execution |
$execution.environment | string | Environment name (e.g. production, staging) |
$execution.startedAt | string | ISO 8601 timestamp of when the execution started |
{{ $execution.id }} // "8cc63dd9-5d0d-436f-aec6-113b66d36259"{{ $execution.workflowId }} // "wf-customer-onboarding"{{ $execution.startedAt }} // "2026-05-27T12:34:56.000Z"A common use case: passing $execution.id as a correlation token to downstream systems (X-Request-Id headers, claim tokens, audit-log fields) so a row touched by this run can be traced back to it.
Operational Errors ($errors)
Section titled “Operational Errors ($errors)”$errors is a running array of every operational and execution error that has occurred in the workflow up to the current step. Use it after Continue on Error to inspect what went wrong without having to remember which step failed.
Each entry has this shape:
{{ $errors | size }} // total entries so far{{ $errors[0].stepId }} // step that produced the error{{ $errors[0].type }} // 'operational' or 'execution'{{ $errors[0].message }} // human-readable error message{{ $errors[0].code }} // machine code (e.g., HTTP_CLIENT_ERROR){{ $errors[0].severity }} // 'error' or 'warning'$errors is populated even when Continue on Error isn’t set — but in that case the workflow halts on the first error, so only the failing step’s entry is visible. With Continue on Error enabled on a step (or globally), downstream steps can branch on $errors to react to upstream failures.
Row-Level Variables
Section titled “Row-Level Variables”When using data transformation steps like map, filter, or reduce, these variables are available within each iteration:
| Variable | Description |
|---|---|
{{ $item }} | Current item being processed |
{{ $original }} | Original item before transformation |
{{ $this }} | Alias for $item (useful for primitives) |
{{ $index }} | Zero-based iteration index |
{{ $isFirst }} | true for the first item |
{{ $isLast }} | true for the last item |
Example in a map step expression:
{{ $item.firstName }} {{ $item.lastName }} ({{ $index }})Inside For Each step iterations (not data-transform rows), {{ $indexPath }} is also available — the array of iteration indexes across all enclosing loops. See Control Flow.