# Branch Workflows
Source: https://learn.workflow.dog/building/branching
Choose values, route execution, and combine conditions without hiding control flow.
Branching in WorkflowDog is data-driven. Conditions produce Boolean values,
and control actions either choose a value or emit data along one path.
## Choose a value or choose a path
The two basic patterns look similar on the canvas but behave differently:
[Choose Value](/reference/actions/control/mux) receives **If True**, **If
False**, and a **Boolean Condition**, then emits exactly one value through
**Result**.
Both candidate inputs are dependencies of the action. Use this when the
upstream values are already available and only the selected result matters
downstream.
[Route Value](/reference/actions/control/demux) receives one **Value** and a
**Boolean Condition**. It emits the value from either **If True** or **If
False**. The other output emits no signal.
A downstream node connected only to the unselected output is not attempted.
Use this when different actions should run on different branches.
For a value choice, connect approved text, rejected text, and the condition to
**Choose Value**, then send its single **Result** to the message action. For an
execution choice, connect the record and condition to **Route Value**; use **If
True** to create the approved record and **If False** to request review.
If both branches ultimately feed the same action, choose a value first and
connect one result. If the branches perform different work, route the value.
## Build conditions
Logic actions turn comparisons and checks into Boolean values:
| Need | Action | Behavior |
| ---------------------- | ------------------------------------------------- | -------------------------------------------------------------- |
| Values are identical | [Equal](/reference/actions/logic/equal) | Uses strict equality; values of different types are not equal. |
| Values differ | [Not Equal](/reference/actions/logic/not-equal) | Uses strict inequality. |
| Every condition passes | [And](/reference/actions/logic/and) | Returns true only when every input is truthy. |
| At least one passes | [Or](/reference/actions/logic/or) | Returns true when any input is truthy. |
| Reverse a condition | [Not](/reference/actions/logic/not) | Negates the input's truthiness. |
| Inspect truthiness | [Is Truthy](/reference/actions/control/is-truthy) | Converts truthiness to an explicit Boolean. |
| Inspect falsiness | [Is Falsy](/reference/actions/control/is-falsy) | Returns true for a falsy value. |
Strict equality makes type conversions important. The number `1` and the
string `"1"` are different values. Convert first when data from an external
system represents numbers or booleans as text.
## Route by case
[Choose Value by Case](/reference/actions/control/mux-case) maps text keys to
values. It is useful for statuses, categories, event types, or any branch with
more than two outcomes.
Connect the text to compare, such as `priority` or `event_type`.
Add one key and value for each recognized case.
Provide **Default** for everything not listed. Without a default, an
unmatched case returns `null`.
Connect **Result** to the common downstream action.
Case keys are exact and case-sensitive. `"High"` and `"high"` are separate
cases.
Choose Value by Case selects data; it does not create multiple execution
outputs. To run different actions, compare the case and use [Route
Value](/reference/actions/control/demux), or add a **Conditional** meta
control to each branch.
## Supply fallback values
[Fallback](/reference/actions/control/coalesce) evaluates candidates in their
configured order and returns the first one that qualifies:
* **Non-Null** skips `null` values but keeps other values, including `false`,
`0`, and an empty string.
* **Truthy** skips every falsy value.
Use **Non-Null** for optional fields where `false` or `0` is meaningful. Use
**Truthy** only when those values should also fall through.
## Gate one action
When a separate branch node would add noise, enable the **Conditional** meta
control on the action. Connect a Boolean condition to the new **Condition**
input. The action runs only when the value is truthy.
This is particularly useful for optional side effects:
For example, save every order but connect **amount exceeds review threshold**
to the **Condition** input on **Notify reviewer**. The notification becomes an
optional side effect without affecting the save path.
If the condition is false, the action is not attempted and its ordinary
outputs emit no signal. Downstream nodes that depend on those outputs will
also be skipped unless another path supplies their inputs.
See [Meta Controls](/building/meta-controls) for status outputs that report
whether a gated action was attempted or succeeded.
## Avoid ambiguous branches
* Name the condition in a nearby [Comment](/reference/actions/core/comment),
especially when `true` and `false` are not self-explanatory.
* Normalize text before exact comparisons when capitalization or whitespace
comes from users.
* Prefer one clear multi-case mapping over a long chain of nested binary
choices.
* Preserve `false` and `0` with a non-null fallback when they are valid
business values.
* Test both selected and unselected paths. A skipped node is different from a
node that ran and returned `null`.
# Connect Data
Source: https://learn.workflow.dog/building/connect-data
Pass values between actions, configure fixed inputs, and expose the exact outputs you need.
Every connection in a workflow carries a value from an output on one node to
an input on another. The connection also creates an execution dependency: the
receiving action waits for the connected output before it runs.
## Static and dynamic inputs
Most inputs can receive their value in one of two ways:
Enter a fixed value directly in the node's configuration. The same value is
used on every run.
Static inputs are a good fit for constants such as a model name, status,
email subject, or other fixed configuration.
Connect an output from another node. The input receives the value produced
during the current run.
Dynamic inputs are required when a value comes from trigger data, an API
response, a calculation, or any other action.
For an input that supports both modes, use **Configure dynamically** to switch
between them. Starting a connection to the input switches it to dynamic mode
automatically.
Switching a connected input back to static configuration removes the
connection to that input. Confirm the fixed value before changing modes.
Some settings are configuration-only and cannot be connected. They define the
shape or behavior of the node itself rather than data for a run.
## Match data types
Handles indicate the kind of value they accept, such as String, Number,
Boolean, List, Object, File, or a package-specific type. Connect compatible
types whenever possible.
An **Any** handle accepts any value, but the receiving action still decides
what values are meaningful. For example, [Parse JSON](/reference/actions/core/json-parse)
accepts a String containing JSON; connecting an arbitrary value does not make
it valid JSON.
Use conversion actions when the types differ:
* [To Number](/reference/actions/core/to-number) converts compatible values to
a number.
* [To Boolean](/reference/actions/core/to-boolean) converts a value using
boolean semantics.
* [Convert to JSON](/reference/actions/core/json-stringify) serializes a value
as JSON text.
* [Parse JSON](/reference/actions/core/json-parse) turns JSON text back into a
structured value.
Preserve a value's native type for as long as possible. Convert objects or
lists to text only when the next system actually requires text.
## Select part of an object
Object-producing actions can expose the whole object and selected properties.
When the node shows **Select Property**, add only the properties downstream
actions need. Each selected property becomes its own output handle.
You can also select a nested property from a completed run:
A real output gives the editor the object's current shape.
Choose the property path from the run result.
The editor exposes that path as a connectable output. For outputs that do
not support property handles directly, it can route the value through [Get
Properties](/reference/actions/objects/get-properties).
Property selection keeps the rest of the workflow readable and avoids passing
a large object into an action that needs only one field.
A property can be absent in a later run even if it appeared in the run you
inspected. Validate optional or external data before relying on it.
## Repeatable inputs
Some nodes accept a variable number of values. Examples include items in
[Create List](/reference/actions/arrays/build), values in
[Fallback](/reference/actions/control/coalesce), and properties in
[Create Object](/reference/actions/objects/build).
Repeatable inputs support two common layouts:
* **Individual items** — Add, remove, and reorder entries, then configure or
connect each one separately.
* **Entire list at once** — Connect one List whose items become the repeatable
input.
Use individual items when the workflow has a small, known set of sources. Use
an entire list when the number of values comes from runtime data.
For key/value inputs, each repeatable row contributes a property to an object.
Keys should be unique; a later duplicate key replaces the earlier property
when the object is assembled.
## Repeatable outputs
Some actions can expose either a complete collection or selected entries. In
individual mode, each configured output corresponds to one position or
property in the result. In whole-list mode, one output carries the collection.
Choose based on what happens next:
* Connect the whole list to actions such as
[Loop Workflow](/reference/actions/core/loop-workflow),
[Join Lists](/reference/actions/arrays/join), or
[Filter With Workflow](/reference/actions/arrays/filter-with-workflow).
* Select individual items when later branches need separate values. For
position-based access, [Get Items by Index](/reference/actions/arrays/get-items)
makes the intended indexes explicit.
## Design reliable connections
Treat a node's outputs as a small contract with its downstream consumers:
1. Connect the narrowest useful value.
2. Keep structured values structured.
3. Convert types at a clear boundary.
4. Account for `null`, missing properties, and empty lists.
5. Run the workflow once and inspect the actual output before building a long
downstream chain.
For data that may be missing, [Fallback](/reference/actions/control/coalesce)
can choose the first non-null or truthy candidate. For a hard requirement,
[Throw Error](/reference/actions/core/throw-error) can stop the run with a
clear message.
# Files and Structured Data
Source: https://learn.workflow.dog/building/files-and-structured-data
Move between files, text, objects, JSON, YAML, and data URLs without losing the intended format.
WorkflowDog treats files, strings, and structured values as different data
types. Keep them distinct until a system boundary requires a conversion.
## Know what you have
| Value | Contains | Typical use |
| ------------------ | ----------------------------------------------------- | ---------------------------------------------------- |
| **File** | A name, MIME type, encoding, and base64-encoded bytes | Uploads, attachments, downloads, images, PDFs |
| **String** | Text | Prompts, messages, CSV text, JSON text, HTML |
| **Object or List** | Structured workflow data | API payloads, records, branching, property selection |
| **Data URL** | A string containing a MIME type and base64 data | Embedded browser or API content |
Changing a filename does not convert bytes, and serializing an object does not
create a File. Use an explicit conversion action so the boundary is visible on
the canvas.
## Create and download files
Use [Create Text File](/reference/actions/files/create-text-file) when the
content already exists as a String. Supply the complete filename, including an
extension. To deliver structured data as a file, convert the value to JSON,
create `report.json` from that text, then upload, attach, or return the
resulting File.
The filename extension is used to infer the MIME type when recognized.
Use [Download File from URL](/reference/actions/files/download-from-url) to
retrieve a public resource. You can provide a filename or let the action derive
one from the URL path. It uses the response's content type when available and
fails for non-success responses.
Download File from URL blocks local, internal, and private network addresses.
It is for public resources, not for reaching services inside a private
network.
## Rename without converting
[Rename File](/reference/actions/files/rename) returns a copy with a new name
while preserving its bytes and MIME type.
Renaming `invoice.png` to `invoice.jpg` still leaves PNG image data inside the
file and preserves the original MIME type. Use a format-specific conversion
action when the content itself must change.
## Convert files to and from data URLs
[Convert File to Data URL](/reference/actions/files/file-to-data-url) creates a
String in this form:
```text theme={null}
data:image/png;base64,iVBORw0KGgo...
```
This is useful when HTML or an API requires embedded content. Base64 increases
the representation's size, so prefer a File when the receiving action accepts
one.
[Convert Data URL to File](/reference/actions/files/data-url-to-file) performs
the reverse operation. Its input must use the exact
`data:MIME_TYPE;base64,DATA` form. The output is named
`converted.EXTENSION`, with the extension derived from the MIME type.
A normal `https://` URL is not a data URL. Download it with **Download File
from URL** instead.
## Parse JSON text
[Parse JSON](/reference/actions/core/json-parse) converts a valid JSON String
into its native value: an Object, List, String, Number, Boolean, or `null`.
```json theme={null}
{
"customer": {
"id": "cus_123",
"active": true
},
"tags": ["new", "priority"]
}
```
After parsing, select the properties downstream actions need. See
[Connect Data](/building/connect-data#select-part-of-an-object) for property
outputs.
Malformed JSON causes the action to fail. JSON requires double-quoted strings
and does not allow comments or trailing commas.
## Serialize values as JSON or YAML
[Convert to JSON](/reference/actions/core/json-stringify) serializes a
workflow value as JSON text. Enable pretty formatting for human-readable
output; compact output is usually better for API requests or storage.
[Convert to YAML](/reference/actions/core/yaml-stringify) emits YAML using
two-space indentation. Its **Use references?** option represents repeated
objects with YAML anchors and aliases. Leave references off when every section
should be standalone and easy to copy.
Serialization is useful at an external boundary:
For example, build an Object, convert it to JSON, then create `payload.json`
from the serialized text.
Do not serialize only to parse the value again in the next node. Connect the
original Object or List directly and preserve its types.
## Validate structured data
[Validate JSON Schema](/reference/actions/utilities/validate-json-schema)
checks any value against a JSON Schema and returns:
* **Is Valid**, a Boolean;
* **Errors**, a list containing every validation error found; and
* the original validated value or top-level property outputs, depending on the
schema.
For an object schema, the node exposes properties declared under the schema's
top-level `properties`. Connect **Is Valid** to
[Route Value](/reference/actions/control/demux) or a **Conditional** meta
control before using those values. One safe pattern is:
1. Parse the JSON text.
2. Validate the parsed value against the schema.
3. Connect both the validated object and **Is Valid** to **Route Value**.
4. Continue processing from **If True**.
5. Use **If False** to record the validator's **Errors**.
Validation does not coerce types. The String `"18"` does not satisfy an
`integer` schema. It also does not strip extra properties, and property outputs
remain the supplied values even when validation fails.
An ordinary schema mismatch returns **Is Valid: false**. Malformed JSON or an
invalid schema fails the action itself. Handle those as separate failure
cases.
## Choose the right conversion
Use **Convert to JSON**. If the API action accepts a structured body
directly, connect the Object instead.
Use **Parse JSON**, then select properties from the resulting value.
Use **Create Text File** and give it the correct filename extension.
Use **Download File from URL**.
Use **Convert File to Data URL**.
# Work With Lists and Loops
Source: https://learn.workflow.dog/building/lists-and-loops
Build, transform, inspect, and process collections without losing order or type information.
A List is an ordered collection of values. Lists can contain text, numbers,
objects, files, or mixed values, and they can be passed between actions as one
value.
## Create a list
Choose the source that matches how the collection is produced:
| Source | Use it when |
| ----------------------------------------------- | ---------------------------------------------------------------------- |
| [Create List](/reference/actions/arrays/build) | You have a known set of individual values. |
| [Create Range](/reference/actions/arrays/range) | You need a numeric sequence. |
| [Append](/reference/actions/arrays/append) | You need to add one value to an existing list. |
| [Join Lists](/reference/actions/arrays/join) | You need to concatenate multiple lists. |
| An integration action | An API already returns records, messages, rows, or another collection. |
On repeatable list inputs, add and reorder individual items or switch to
providing an entire List at once. Individual inputs are best for a fixed set;
the whole-list input is best for runtime collections.
## Inspect and reshape lists
List actions transform a collection without requiring a sub-workflow:
* [Get Items by Index](/reference/actions/arrays/get-items) exposes selected
positions as separate outputs. Index `0` is the first item, and `-1` is the
last.
* [Slice](/reference/actions/arrays/slice) returns a contiguous section.
* [Chunk](/reference/actions/arrays/chunk) splits a list into smaller lists.
* [Flatten](/reference/actions/arrays/flatten) removes nested list levels.
* [Unique](/reference/actions/arrays/unique) removes repeated values.
* [Sort](/reference/actions/arrays/sort) reorders the items.
* [Length](/reference/actions/arrays/length) returns the item count.
Use these focused actions before reaching for a loop. They make the workflow
easier to read and avoid starting a child workflow for work a single action can
perform.
## Process every item
[Loop Workflow](/reference/actions/core/loop-workflow) runs a callable workflow
once for each item in **Payloads**.
Give the child workflow the [Sub-Workflow
trigger](/reference/triggers/core/callable). Read the current item with
[Data from Trigger](/reference/actions/core/trigger-data).
Connect the transformed value to [Return
Data](/reference/actions/core/return-data).
In the parent workflow, select the child in **Loop Workflow** and connect
the source list to **Payloads**.
**Results** contains one child result for each input item, in the same
order.
Iterations run sequentially. This preserves ordering and avoids overlapping
child runs, but the total runtime grows with both the number of items and the
duration of each child workflow.
A child that finishes without **Return Data** contributes `null` at its
position. If a child run fails, the loop action fails instead of returning a
partial results list.
Loop Workflow accepts up to 1,000 payloads. Split larger collections into
batches before invoking it.
## Filter with a predicate workflow
[Filter With Workflow](/reference/actions/arrays/filter-with-workflow) runs a
callable workflow for each item and keeps the original items whose returned
value is truthy.
The predicate workflow should:
1. Read the item from **Data In**.
2. Compare or validate it.
3. Return the decision through **Return Data**.
The output keeps matching items in their original order. The returned decision
does not need to be a Boolean, but an explicit Boolean makes the predicate's
intent clearer.
For example, filter a list of orders with a **Needs review?** predicate, then
send the matching orders to a **Create review task** loop workflow.
Like Loop Workflow, filtering is sequential, accepts at most 1,000 payloads,
and fails if any child run fails.
## Find the first match
[Find With Workflow](/reference/actions/arrays/find-with-workflow) tests items
from the beginning and returns the first original item whose predicate result
is truthy. It stops testing after a match and returns `null` when none match.
Use it instead of filtering when:
* only one item is needed;
* list order defines priority; or
* avoiding unnecessary child runs matters.
## Preserve the difference between an item and a result
The three workflow-backed list actions return different things:
| Action | Output |
| ------------------------ | ----------------------------------------------------- |
| **Loop Workflow** | The value returned by the child for every item. |
| **Filter With Workflow** | The original items whose child result is truthy. |
| **Find With Workflow** | The first original item whose child result is truthy. |
If you need both an original item and derived fields, have the loop child
return an object containing both. [Create Object](/reference/actions/objects/build)
can assemble a predictable result such as:
```json theme={null}
{
"source": {
"id": "order_123",
"total": 249
},
"requires_review": true,
"reason": "Order total exceeds threshold"
}
```
## Choose a list strategy
Use a dedicated Arrays action. It runs in the current workflow and
communicates the operation directly.
Use **Loop Workflow** and put the per-item sequence in a callable child
workflow.
Use **Filter With Workflow** with a predicate child workflow.
Use **Find With Workflow**. Put the highest-priority candidates first.
External side effects completed by earlier iterations are not rolled back if a
later child fails. Design loop children so they can be retried safely when
they create records, send messages, or modify remote state.
# Use Meta Controls
Source: https://learn.workflow.dog/building/meta-controls
Gate, order, observe, and debug any action without changing its core behavior.
Meta Controls add execution inputs and diagnostic outputs to an action. Select
one node and open **Meta Controls** from its selection toolbar or configuration
panel.
They are available independently of the action's package, so the same control
patterns work across integrations and built-in actions.
## Available controls
| Meta Control | Adds | Behavior |
| ----------------------- | ---------------------------- | -------------------------------------------------------- |
| **Conditional** | **Condition** input | Runs the action only when the connected value is truthy. |
| **Wait For** | **Wait For** input | Delays the action until the connected output emits. |
| **Did Action Attempt?** | **Attempted?** output | Reports whether the action itself was invoked. |
| **Did Action Succeed?** | **Succeeded?** output | Reports whether it ran without an error. |
| **Error** | **Error** output | Exposes the action's error message when it fails. |
| **Outputs As Object** | **Outputs As Object** output | Collects all ordinary action outputs into one object. |
Turning off a control removes its handle and any connection attached to that
handle.
## Run an action conditionally
Enable **Conditional** and connect a condition to **Condition**. For example,
connect an **Is order total greater than 500?** result to the **Condition**
input on **Notify reviewer**.
When the condition is falsy, the action is not attempted. Its ordinary outputs
emit no signal, so nodes that depend on them do not run.
This differs from an action that runs successfully and returns `null`: a
`null` result is still a value, while a skipped action produces no ordinary
output signal.
Use [Route Value](/reference/actions/control/demux) instead when both the true
and false paths should perform visible work. See
[Branch Workflows](/building/branching) for the choice between gating and
routing.
## Add an ordering dependency
Connections normally carry both data and execution order. Sometimes one action
must wait for another even though it does not need the earlier action's value.
Enable **Wait For** and connect any output from the prerequisite:
In a customer-onboarding workflow, connect an output from **Create customer**
to **Wait For** on **Send welcome email**. Connect the email address separately
to the send action's **To** input.
The connected output's value is not passed into the action's ordinary inputs.
It only establishes that the output must emit first.
Wait For requires an emitted value. If the upstream node is disabled, skipped,
fails, or takes an unselected routing path, the waiting action is not
attempted.
## Observe whether an action ran
**Attempted?** and **Succeeded?** answer different questions:
| Outcome | Attempted? | Succeeded? |
| ------------------------------------------------------------------------ | ---------- | ---------- |
| Action completed successfully | `true` | `true` |
| Action ran and threw an error | `true` | `false` |
| Action was disabled, skipped by a condition, or lacked a required signal | `false` | `false` |
These status outputs are useful for reporting and cleanup paths that must
distinguish “did not run” from “ran and failed.”
Because meta-control outputs are settled even when ordinary outputs are not,
they can drive downstream diagnostics after a failure or skip.
## Capture an error message
Enable **Error** to expose the formatted error from the action:
* a failed action emits its error message;
* a successful attempted action emits `null`; and
* an action that was not attempted emits no error value.
Pair it with the status outputs when the distinction matters:
Connect **Attempted?**, **Succeeded?**, and **Error** to **Create Object**, then
send that object to the action that records the result. This keeps the three
diagnostic values together without hiding which signal each field represents.
Exposing **Error** does not turn a failed action into a successful one or
retry it. It makes failure data available for diagnostic paths.
## Collect outputs for inspection
**Outputs As Object** bundles the action's ordinary returned outputs into one
Object. It is primarily useful for:
* inspecting a node with many outputs;
* passing a complete result into a log or sub-workflow; or
* capturing a snapshot while debugging.
On success, the object contains the outputs returned by the action. When the
action does not produce results, it emits `null`.
Prefer named output handles for long-lived production connections. They make
dependencies explicit and avoid coupling downstream nodes to every field the
action returns.
## Disable nodes temporarily
Disabling is a selection action rather than a Meta Control, but it participates
in the same execution semantics. Select one or more nodes and choose
**Disable**; choose **Enable** to restore them. Disabled nodes are not
attempted, and their ordinary outputs emit no signal.
On macOS, the shortcut is `⌘ ⇧ E`.
Use disabling to isolate part of a workflow during development. Before
shipping, check every downstream dependency: disabling a producer can skip
more than the selected node.
## Debug a branch deliberately
For an action whose execution is unclear, temporarily enable:
1. **Did Action Attempt?**
2. **Did Action Succeed?**
3. **Error**
4. **Outputs As Object**
Run representative true, false, successful, and failing cases. The four
outputs reveal whether the action was eligible, whether it completed, why it
failed, and what it returned. Remove diagnostic controls you no longer need so
the production graph keeps a clear contract.
# Organize the Canvas
Source: https://learn.workflow.dog/building/organizing-the-canvas
Select, arrange, label, highlight, and pin nodes as workflows grow.
A readable canvas makes execution order, data ownership, and failure paths
visible. WorkflowDog provides selection tools, automatic layout, comments,
highlights, and pinned actions for keeping large workflows navigable.
## Select the nodes you mean to change
| Action | Result |
| ------------------------------------ | ------------------------------------------------ |
| Click a node | Selects that node. |
| Shift-click a node | Adds it to or removes it from the selection. |
| Hold Option and drag on empty canvas | Selects nodes whose centers fall inside the box. |
| `⌘ A` | Selects every node. |
| `⇧ ←` | Adds the selected nodes' direct incomers. |
| `⇧ →` | Adds the selected nodes' direct outgoers. |
| Click empty canvas | Clears the selection. |
Dragging one selected node moves the whole selection. Once selected, the
floating toolbar provides layout, alignment, highlight, duplicate, copy, cut,
disable, extraction, and deletion actions.
Keyboard shortcuts above use macOS symbols. The corresponding modifier keys
may differ on another operating system.
## Lay out a selection
Select at least two nodes and choose **Auto Layout**, or press `⌘ ⇧ L`. The
layout follows graph connections and arranges the selected actions from left to
right.
Use the additional selection tools for smaller adjustments:
* **Auto align top/left** — `⌘ ⇧ A`
* **Auto align center** — `⌘ ⇧ S`
* **Auto align bottom/right** — `⌘ ⇧ D`
The editor chooses horizontal or vertical alignment based on the shape of the
selection and keeps at least a small gap between aligned nodes.
Auto-layout the functional nodes first, then adjust comments and explanatory
spacing. Repeated manual pixel adjustments are rarely worth preserving.
## Lay out the entire workflow
Choose **Auto Layout Entire Workflow** in the main toolbar or press `⌘ ⇧ G`.
The full layout uses the graph's dependencies and keeps visual groups together.
If a group includes a [Comment](/reference/actions/core/comment), the
upper-left comment acts as a heading above the group's functional nodes. This
makes a consistent pattern effective:
* Add a **Validate order** comment above the actions that parse input, validate
the schema, and route valid and invalid data.
* Add a **Fulfill order** comment above the actions that create the shipment
and notify the customer.
Automatic layout is deterministic from the graph and current groups, but it is
still a structural tool. Review long edge crossings and adjust the few places
where business meaning benefits from extra space.
## Add comments
[Comment](/reference/actions/core/comment) displays Markdown directly on the
canvas. It has no runtime output and never affects execution.
Use comments for:
* a section heading;
* the business rule behind a condition;
* the expected shape of a sub-workflow payload;
* an important external-system assumption; or
* a maintenance note that belongs with the graph.
Comments support left, center, or right alignment and small, medium, or large
text.
Comments are visible to people who can view the workflow. Never place API
keys, passwords, access tokens, or other secrets in them.
Write comments about intent rather than narrating an obvious node. **Orders
over \$500 require manual review before fulfillment** is more useful than
**Checks if amount is greater than 500** because it records the business rule,
not merely the comparison.
## Highlight related nodes
Select nodes and choose **Highlight Color** from the selection toolbar. Nearby
nodes with the same color form a dashed visual group.
Highlights are most useful when each color has a stable meaning within one
workflow, such as:
* blue for input normalization;
* violet for AI processing;
* green for successful side effects; and
* red for validation or failure handling.
Clicking a group border selects the group. Shift-clicking toggles it alongside
the current selection, and dragging the border moves the grouped nodes
together.
Auto-layout treats nearby groups as units, which helps preserve sections while
rearranging the full workflow.
Color is organizational metadata, not execution logic. Use connections,
branching actions, and meta controls to define actual behavior.
## Pin frequently used actions
Open action search with `/`, `⌘ K`, or `⌘ P`. In the search results, pin an
action to place it in the main toolbar. Pinned actions can be reordered with
the left and right controls in the search result.
From the toolbar:
* click a pinned action to add it at the center;
* drag it onto a specific canvas position; or
* press its slot number, from `1` through `9`, to add it at the pointer.
Pins are stored for the current browser, so they personalize the editor rather
than changing the workflow for collaborators.
Keep the set small and focused on the primitives you actually repeat. Text,
Number, Create Object, Comment, and the control actions you use most often are
good candidates.
## Refactor a dense section
When a section is internally coherent but makes the parent workflow hard to
scan:
1. Select its functional nodes.
2. Choose **Extract to Sub-Workflow**.
3. Inspect the new payload and result boundary.
4. Give the child a specific name.
5. Add a comment beside the caller describing the contract.
The extraction works most cleanly with one incoming and one outgoing boundary
connection. See [Build Sub-Workflows](/building/sub-workflows#extract-selected-nodes)
before extracting a selection with several independent inputs or outputs.
## A practical organization pass
For an existing workflow, use this order:
Identify the trigger data, primary transformations, and final side effect.
Make that path easy to read from left to right.
Place validation, fallback, and failure paths consistently above or below
the main path.
Select connected sections and use Auto Layout before arranging the entire
workflow.
Add comments for rules and contracts that the node names cannot explain.
Group nodes by responsibility, not by package or arbitrary visual variety.
Move a sequence into a sub-workflow when it has a clear interface or is used
from more than one place.
A well-organized canvas should let a reader answer three questions quickly:
what starts the workflow, what decisions it makes, and what external changes it
can perform.
# Build Sub-Workflows
Source: https://learn.workflow.dog/building/sub-workflows
Extract reusable workflow logic, define its input and output, and call it safely.
A sub-workflow packages a reusable sequence behind one input and one returned
value. It can be called from another workflow, used as the body of a loop, or
used as a custom list predicate.
## The callable workflow contract
* The [Sub-Workflow trigger](/reference/triggers/core/callable) allows another
workflow to start it.
* [Data from Trigger](/reference/actions/core/trigger-data) exposes the
caller's payload as **Data In**.
* Reusable actions transform or act on that input.
* [Return Data](/reference/actions/core/return-data) sends one value back to a
waiting caller.
The input and output can be any supported value. For a stable interface,
prefer an object with named properties over a positional list or an
undocumented block of text.
## Create one manually
Choose **When another workflow calls this one** as its trigger.
Add **Data from Trigger** and connect **Data In** to the actions that need
the caller's payload.
Add validation, integrations, and transformations as you would in any
workflow.
Add **Return Data** and connect the result. A waiting caller receives `null`
if the child finishes without returning data.
Add [Run Workflow](/reference/actions/core/run-workflow) to the parent,
select the child, and connect its payload.
## Call once
[Run Workflow](/reference/actions/core/run-workflow) starts the selected
callable workflow and waits for it to finish.
| Parent input or output | Child meaning |
| ---------------------- | ----------------------------------------------------------- |
| **Payload** | Becomes **Data In**. |
| **Result** | Receives the value sent through **Return Data**, or `null`. |
If the child fails, Run Workflow fails with the child's failure message. This
makes validation and errors in the child visible to the parent.
## Call for a list
Use [Loop Workflow](/reference/actions/core/loop-workflow) when the same child
should process multiple payloads. It starts one child at a time and returns one
result per item in the same order.
Custom list predicates use the same interface:
* [Filter With Workflow](/reference/actions/arrays/filter-with-workflow) keeps
items whose child returns a truthy value.
* [Find With Workflow](/reference/actions/arrays/find-with-workflow) returns
the first item whose child returns a truthy value.
See [Lists and Loops](/building/lists-and-loops) for the behavioral differences
and limits.
## Select a workflow dynamically
The **Selected Workflow** input can be fixed in the node or supplied as a
Workflow value. [Workflow](/reference/actions/core/workflow) resolves a
callable workflow from the current project and exposes that typed value.
Dynamic selection is useful when an earlier branch chooses among several
implementations with the same input/output contract. Keep the contract
consistent; the editor cannot prove that two arbitrary workflows return the
same shape.
## Extract selected nodes
The canvas can turn an existing selection into a sub-workflow:
Select the connected actions you want to move.
The editor creates and enables a callable workflow, moves the selected
actions into it, and adds a configured **Run Workflow** node in their place.
When the selection has exactly one connection entering and one leaving, the
editor bridges them through the new payload and result.
Rename the new workflow and add a [Comment](/reference/actions/core/comment)
describing its expected input, returned output, and failure behavior.
Review extracted workflows before relying on them. Selections with multiple
inbound or outbound boundary connections cannot be represented by one
automatic payload or result connection. Package multiple values into an object
before extraction, or reconnect the interface manually afterward.
## Design a durable contract
Use an object for any interface likely to grow:
```json theme={null}
{
"customer_id": "cus_123",
"order_id": "ord_456",
"notify": true
}
```
Return a similarly named object:
```json theme={null}
{
"status": "processed",
"record_id": "rec_789"
}
```
This makes call sites self-describing and lets you add optional properties
without changing the meaning of existing positions.
## Failure and recursion behavior
* A failure propagates through callers that wait, including **Run Workflow**,
**Loop Workflow**, and workflow-backed filter/find actions.
* A child with no **Return Data** produces `null`; that is a successful run,
not a failure.
* Loop and predicate callers fail rather than returning partial results when a
child fails.
* Recursive workflow calls are rate-limited to prevent infinite recursion.
Put reusable business logic in a sub-workflow, but leave orchestration in the
parent. A focused child with a clear input, output, and error contract is
easier to test and reuse than a large child that controls the entire process.
# Actions
Source: https://learn.workflow.dog/essentials/actions
Add, configure, and connect the nodes that perform work in a workflow.
Actions are the working parts of a workflow. An action can call a service,
transform text, make a decision, wait for a dependency, run another workflow,
or return a result. Each action appears as a node on the canvas.
## Add an action
Press /, ⌘ K, or ⌘ P to open action search.
Search by action name, package, or related keyword, then select a result to add
it to the canvas.
The picker groups actions by package. For example, **Core** contains general
workflow tools, while Gmail, HTTP, and Google Sheets contain service-specific
operations. You can pin actions you use frequently so they stay available in
the editor toolbar.
Search for the outcome you want, such as `respond`, `format date`, or `get
row`. You do not need to know the package first.
## Configure an action
Select one node to open its configuration panel. Inputs can appear in the
panel, on the node, or in both places depending on how the action is designed.
There are three common input modes:
| Mode | Use it for |
| ---------------------- | -------------------------------------------------------------------------- |
| **Fixed value** | Text, numbers, choices, and other values that stay the same between runs. |
| **Connected value** | Data produced by the trigger or another action during the current run. |
| **Fixed or connected** | Inputs with a function control that can switch between the two approaches. |
Required inputs must receive a valid value before the action can succeed.
Optional inputs may have a default or may be omitted. Hover an input handle to
see its description, declared data type, requirement, and connection state.
The editor can connect values whose declared types do not match. A connection
may therefore look valid on the canvas but fail when the action validates its
inputs at runtime. Check the input and output types before testing.
## Connect actions
Drag from an output handle to an input handle. The connection passes the value
and makes the target action wait for that source.
* An input accepts one connection.
* An output can feed several actions.
* Independent branches are eligible to run concurrently.
Object outputs can expose the entire object and selected properties. Choose the
properties you need instead of passing a large object into an action that
expects one field. Some repeatable inputs also let you switch between separate
entries and one entire list.
During an inspected run, output handles can show the actual value that action
produced. This is useful for finding the right object property before wiring
the next action. See [Workflow runs](/essentials/workflow-runs) for the run
inspection tools.
## Control the node
Select one or more actions to access common canvas operations:
* enable or disable the selection,
* duplicate, copy, cut, or delete it,
* align or automatically lay out several nodes,
* select connected upstream or downstream actions, and
* extract a selection into a sub-workflow.
A disabled action is skipped. Its normal outputs do not produce values, so
downstream actions that require those outputs are skipped as well.
For per-run control, an action can expose meta controls such as **Conditional**
and **Wait For**, plus outcome values such as **Did Action Succeed?** and
**Error**. Learn how to build those branches in
[Meta controls](/building/meta-controls).
## Choose the right action
The action picker gives a short description. The
[Actions reference](/reference/actions) provides the full contract for every
built-in action:
* what the action does,
* each input and its type,
* each output and its type,
* relevant limits and edge cases, and
* setup or troubleshooting details when needed.
Use the exact name shown in the picker to find the corresponding reference
page. For events that begin a workflow, use the
[Triggers reference](/reference/triggers) instead.
# Enable and pause workflows
Source: https://learn.workflow.dog/essentials/enable-and-pause
Control whether new trigger events are allowed to execute a workflow.
A workflow is either **Live** or **Paused**.
* **Live** workflows accept trigger events and queue runs when project usage
requirements are satisfied.
* **Paused** workflows reject newly created runs before execution.
New workflows start Paused so you can configure the trigger and graph before
allowing events to execute actions.
## Enable a workflow
Open the trigger drawer, select any required account, and complete the
trigger-specific settings.
Confirm the editor shows **Saved**. Enabling does not force a pending graph
save to finish first.
Confirm selected accounts are healthy. For billable triggers, confirm the
project has run credits or active usage billing.
Open the status menu at the top of the editor and choose **Enable Workflow**.
The status changes to **Live**.
Trigger the workflow and inspect its new run in **Run History**.
## Pause a workflow
Open the **Live** status menu and choose **Pause Workflow**. The status changes
to **Paused**.
Pausing is immediate for runs created after the status update, but it is not a
subscription teardown or queue purge.
Pausing does not cancel runs that are already Scheduled. Those delayed runs
remain queued and can execute at their scheduled time. Cancel each Scheduled
run from run history when it must not execute.
## What happens to events while paused
External trigger subscriptions remain configured while the workflow is
paused. When a trigger event tries to start the workflow:
1. WorkflowDog creates a run record from the event.
2. The eligibility check sees that the workflow is paused.
3. The run is marked **Failed** with **The workflow is paused**.
4. The event is not queued for later execution.
Enabling the workflow later does not replay these paused-event failures.
The same rule applies to manually choosing **Re-run** while the workflow is
paused: the new run fails the paused eligibility check.
Keeping the external subscription configured makes pause and resume fast and
avoids repeatedly creating provider webhooks or watches. It also means run
history can show failed paused events.
## Pausing and scheduled work
A Schedule Workflow action reserves and queues its delayed run when the parent
workflow executes. The destination workflow's Live or Paused state is checked
at that queueing moment.
If the destination is Live when the run is scheduled and becomes Paused later,
the existing Scheduled run is not checked again before execution. Cancel it
explicitly if the pause should include already scheduled work.
## Pausing and integrations
Pausing does not:
* Disconnect integration accounts.
* Revoke provider permissions.
* Remove Gmail watches, Microsoft subscriptions, or other external event
sources.
* Clear trigger configuration.
Use [Integrations](/essentials/integrations) to replace or disconnect an
account. See [External triggers](/essentials/external-triggers) for the
subscription lifecycle.
## Billing can still stop a Live workflow
**Live** means the workflow is allowed to run; it does not bypass project usage
checks. A Live workflow can create a Failed run when:
* The project has no run credits and no usage subscription.
* The subscription exists but its payment state does not allow new usage.
Resolve the project issue under
[Usage and billing](/essentials/usage-and-billing), then send a new event or
manually re-run the saved payload.
## When to pause
Pause a workflow when:
* Editing actions that send messages or change external data.
* Rotating an integration account.
* Investigating repeated bad inputs.
* Preventing new work while you cancel already Scheduled runs.
For a planned account migration, pause first, swap action usages, reconfigure
the trigger, confirm the new account is healthy, and then enable the workflow.
## Troubleshooting
Check whether it was already in Scheduled status before the pause. Pausing
blocks newly queued work but does not cancel delayed runs that were already
accepted.
The trigger subscription is still receiving events. This is expected while
paused. Enable the workflow when ready, or reconfigure/disconnect the trigger
source when you need events to stop at the provider.
Open the failure tooltip. Out-of-credit and invalid-payment failures are
project billing problems, while a worker failure is an execution-system
problem.
Confirm the workflow is Live and the project can accept billable runs. A
manual re-run goes through the same pause and billing checks as a trigger
event.
# External triggers
Source: https://learn.workflow.dog/essentials/external-triggers
Configure and operate provider-backed event subscriptions safely.
An **external trigger** listens for events from another service, such as a new
Gmail message, a Google Forms response, a Microsoft Outlook message, or a
TidyCal booking.
The trigger's account and settings describe the event source. When the
provider sends an event, WorkflowDog converts it into one or more workflow runs.
## Configure an external trigger
Create a workflow and choose the provider event that should start it.
Open **Configure Trigger**, select a healthy integration account, and approve
any required permissions.
Choose the mailbox, label, form, or other trigger-specific source. See that
trigger's reference page for its exact fields.
Wait for the trigger configuration to finish updating. WorkflowDog creates or
adopts the required provider subscription during configuration.
Set the workflow Live, send a new provider event, and inspect the resulting
run.
External event sources are configured even while the workflow is Paused. Live
or Paused controls run eligibility; it is not the switch that creates or
removes the provider subscription.
## How subscriptions are reused
WorkflowDog creates a deterministic identity for each logical event source. If
multiple workflows need the same underlying source, they can share one
provider subscription instead of creating duplicates.
For example, two workflows can listen to different event types delivered by
the same account-backed provider subscription. WorkflowDog tracks which
workflow and trigger type should receive each event.
This sharing affects cleanup:
* Changing one workflow removes only the source relationship it no longer
needs.
* If another workflow still uses the source, the provider subscription stays
active.
* If no workflow uses it, WorkflowDog cleans up the external resource and
deletes the source.
## Change trigger configuration
Saving a new trigger configuration performs a reconciliation:
1. WorkflowDog derives the event sources required by the new settings.
2. It creates or adopts those sources.
3. It removes obsolete relationships from the workflow.
4. It tears down an obsolete provider subscription only when nothing else uses
it.
This is why account and source changes should be made through **Configure
Trigger** instead of by editing raw workflow data.
After a material change, send a new event that matches the new configuration.
Changing the source does not replay events that occurred under the old
configuration.
## Pause without removing the subscription
When a workflow is Paused, external subscriptions continue receiving events.
Each attempted run is recorded as Failed with **The workflow is paused** and is
not queued for later.
Use Paused for temporary execution control. If you need the provider
subscription itself removed, change the trigger configuration, disconnect the
account, or delete the workflow.
Read [Enable and pause workflows](/essentials/enable-and-pause) for scheduled
run behavior and other pause caveats.
## Reconnect an account-backed trigger
Provider credentials can expire, be revoked, or lose permissions. WorkflowDog
marks an account unhealthy when it can no longer use it and notifies Editors
of projects linked to that account.
Reconnecting updates the credentials and starts best-effort background recovery
for account-backed event sources. A source that needs fresh setup is torn down
and recreated while preserving the workflows and event types that used it.
Recovery is asynchronous and is not a guarantee that events missed during an
account or provider outage will be replayed. After reconnecting, verify the
trigger and send a new event.
If a provider renewal worker exhausts its retries, the event source is marked
unhealthy. A later setup or account-recovery cycle can rebuild it from scratch.
## Disconnect an account
Disconnecting an account from a project clears matching account values from
trigger configurations. WorkflowDog processes those trigger updates normally,
so obsolete event-source links and unused provider subscriptions are cleaned
up.
Before disconnecting:
1. Connect the replacement account.
2. Pause workflows that can cause side effects.
3. Reconfigure every trigger that uses the old account.
4. Send a test event through the replacement.
5. Disconnect the old account.
The Integrations page's **Swap Accounts** tool does not update trigger
configurations. See [Integrations](/essentials/integrations).
## Delete workflows and projects
Deleting a workflow removes its event-source relationships. Shared sources stay
active for other workflows; unshared sources are cleaned up.
Deleting a project cleans up event sources for its workflows before the project
and its data are deleted.
## Operate triggers reliably
* Use a dedicated service account when employee access may change.
* Grant every permission required by the trigger, not only by its downstream
actions.
* Treat a **Needs Reconnecting** badge as an operational incident.
* Send a new test event after changing an account or event filter.
* Inspect run history for Paused, billing, or node errors before assuming the
provider subscription is broken.
* Do not rely on automatic backfill unless the individual trigger reference
explicitly documents it.
## Troubleshooting
Confirm the workflow is Live, then inspect history for a Paused or billing
failure. Check the integration account for **Needs Reconnecting**, review
the trigger filters, and send a new event after correcting the issue.
This is expected. Pausing rejects new runs but keeps the provider subscription
configured. Reconfigure or disconnect the trigger source when you need the
external subscription removed.
Accounts are project resources, and disconnecting an account clears its
references across the project. Reconfigure affected workflows with a
replacement account before disconnecting.
Open and save the trigger configuration to run source reconciliation, then
send a new matching event. Also verify provider-side filters and
permissions. If the issue continues, reconnect the account.
# Integrations
Source: https://learn.workflow.dog/essentials/integrations
Connect, select, reconnect, swap, and disconnect external accounts.
An **integration account** lets actions and triggers access an external
service, such as Google, Microsoft, Airtable, or OpenAI. Accounts are linked to
a project, then selected on the nodes and triggers that use them.
## Connect an account
The first connection starts inside the workflow editor, not on the project's
**Integrations** page.
Add an action that uses the service, or open a trigger that requires the
service.
Find **Third-party account** and choose **Connect new account**.
OAuth integrations open the provider's authorization page. API-key
integrations open a credential dialog in WorkflowDog. Approve the permissions
required by the current action or trigger.
After a successful connection, the new account is selected automatically.
It also appears on the project's **Integrations** page.
The first account connected for a provider in a project becomes that
provider's default account.
## Select the right account
Each account selector lists accounts for the current provider and project. A
node can use an account only when it is healthy and has every permission the
node requires.
When an account input has never been set, WorkflowDog selects the healthy
default account if it has the required permissions. An explicit account
selection is preserved until it is cleared, disconnected, becomes unhealthy,
or no longer satisfies the node's permission requirements.
Use **Clear Selection** when a node should not inherit or retain the current
account.
## Manage connected accounts
Open **Integrations** from the project dashboard to see accounts grouped by
provider.
For each account, you can:
* **Set as Default** — Make it the automatic choice for unset account inputs
from the same provider.
* **View Account Usage** — Find action nodes whose saved graph contains the
account.
* **Swap Accounts** — Replace the account on selected action-node usages with
another account from the same provider.
* **Disconnect** — Remove the account from the current project and clear its
saved references.
Defaults are project-specific. Setting a Google account as the default in one
project does not make it the default in another.
## Swap action nodes to another account
Account swapping is useful before disconnecting an old employee account or
rotating a service account.
Connect the new account to the project and ensure it has the permissions
required by the affected actions.
On **Integrations**, open the old account's menu. Under **Account Usage**,
select the workflow and action-node locations to update.
The replacement must belong to the same provider. Select it and choose **Swap
Accounts**.
Open any trigger that uses the old account and select the replacement
manually.
**Account Usage** and **Swap Accounts** cover action nodes only. Trigger
configurations are not listed or swapped by this tool.
## Approve missing permissions
Different nodes from the same provider can require different OAuth scopes. If
an existing account is missing a required permission, click it in the account
selector and complete authorization again.
WorkflowDog requests the new permissions together with the account's existing
permissions. Google reconnections show the consent screen again so Google can
issue refreshed credentials.
After reconnecting, review the node selection. An account that lacked required
permissions may have been cleared from the input before the reconnection.
## Reconnect an unhealthy account
An account marked **Needs Reconnecting** has credentials that WorkflowDog can
no longer use. Actions using it can produce node errors, and account-backed
triggers can stop receiving new events.
Open an account selector and click the unhealthy account. OAuth providers
take you through authorization again.
Refresh the account list and confirm the warning is gone.
Open each account-backed trigger and confirm its configuration. Reconnection
starts background recovery for event subscriptions that need rebuilding.
Test with a new email, form response, or provider event. Do not assume an
event missed during the outage will be replayed.
If reconnection continues to fail, revoke WorkflowDog from the provider's own
connected-app settings, then connect the account again.
## Disconnect an account
Disconnecting performs more than removing an account from the list:
* The project-to-account link is removed.
* Matching account selections in action-node graphs are changed to no
selection.
* Matching account selections in trigger configurations are cleared.
* Trigger event sources are reconciled, including cleanup of external
subscriptions that are no longer used.
Disconnecting does not revoke WorkflowDog at the external provider. Use the
provider's security or connected-app settings when you also need to revoke the
authorization itself.
Swap action usages and reconfigure triggers before disconnecting when workflows
must continue without interruption.
## Troubleshooting
The account is unhealthy or lacks a permission required by that node. Click
the account to reconnect and approve the missing permissions, then refresh
the selector.
Connect the first account from an action or trigger in the workflow editor.
The Integrations page manages accounts after they have been linked to the
project.
Swapping is limited to action-node usages. Open the trigger configuration and
choose the replacement account manually.
Account links are project-specific. Connect the account from a workflow in
the second project before trying to select it there.
Learn how account-backed event subscriptions behave in
[External triggers](/essentials/external-triggers).
# Projects
Source: https://learn.workflow.dog/essentials/projects
Organize workflows, data, integrations, and teammates in a project.
A **project** is the top-level container in WorkflowDog. Its workflows,
workflow runs, variables, connected accounts, team, and billing settings are
kept together.
WorkflowDog does not have a separate workspace layer. When you choose a
project, you are choosing the complete working context for everything in the
project dashboard.
## Create a project
Use the project switcher and choose the option to view your projects.
Select **Create Project**, enter a name, and confirm. The person who creates
the project starts with Editor access.
Open **Workflows**, select **Create a Workflow**, and choose the trigger
that should start it. Workflow creation is trigger-first; there is not a
workflow template picker.
## What belongs to a project
| Project resource | Scope |
| --------------------- | --------------------------------------------------------------------- |
| **Workflows** | Can use other workflows and variables in the same project. |
| **Workflow runs** | Appear in the project's combined run history. |
| **Project variables** | Can be read or changed by any workflow in the project. |
| **Integrations** | Accounts are linked to the project before its workflows can use them. |
| **Team and roles** | Access is granted per project. |
| **Usage and billing** | Run credits, usage charges, and seats are tracked per project. |
Moving a workflow between projects is not available. Create the workflow in
the project whose integrations, variables, team, and billing it should use.
## Switch projects
Open the project switcher from the dashboard sidebar, search by project name,
and choose a project. When possible, the switcher keeps you on the equivalent
dashboard section—for example, switching from one project's **Variables** page
opens **Variables** in the destination project.
The P shortcut opens the project switcher when focus is not inside
another input.
## Organize workflows with folders
The **Workflows** page supports nested folders. Create a folder, create
subfolders from its menu, and drag workflows between folders or back to the
project root.
Deleting a folder does not delete its workflows:
* Workflows in a nested folder move to the deleted folder's parent.
* Workflows in a top-level folder move back to the project root.
* Nested folders inside the deleted folder are removed.
Workflow folders are stored in the current browser's local storage. Folder
names, nesting, collapsed state, and workflow assignments are not shared with
teammates or synchronized to another browser or device. The workflows
themselves remain project data.
If folders disappear after clearing browser data or changing devices, the
workflows are still available at the project root.
## Rename a project
Open the project overview, select the project name or its menu, and choose
**Rename Project**. Renaming changes the project label without changing its
workflows, integrations, or URL identifier.
Only an Editor can rename a project. See
[Team and permissions](/essentials/team-and-permissions) for role details.
## Delete a project
Project deletion permanently removes the project and its associated workflows,
runs, variables, integration links, invitations, and other project data. It
also cancels an active usage subscription for that project.
Project deletion cannot be undone. Confirm that you no longer need the
project's run history or variable values before deleting it.
An Editor can delete the project from the project overview menu. Because
Editors have broad project control, grant that role only to trusted teammates.
## Troubleshooting
The switcher lists only projects where your account is a member. Confirm
that you accepted the invitation while signed in with the invited email
address and that another Editor has not removed you.
This is expected. Folder organization is local to each browser. Search for the
workflow by name, then recreate any local folder structure you want on that
device.
Those actions require Editor access. A Viewer can inspect project resources
but cannot change project settings.
# Team and permissions
Source: https://learn.workflow.dog/essentials/team-and-permissions
Invite teammates and control who can view or change a project.
Project membership controls access to every workflow, run, variable, and
integration linked to a project. WorkflowDog currently has two project roles:
**Viewer** and **Editor**.
## Roles
| Capability | Viewer | Editor |
| ----------------------------------------------- | :----: | :----: |
| View workflows and project settings | ✓ | ✓ |
| Inspect workflow runs, outputs, and errors | ✓ | ✓ |
| View project variables and integration accounts | ✓ | ✓ |
| Build, rename, enable, or delete workflows | | ✓ |
| Clear variables or manage integrations | | ✓ |
| Invite, remove, or change teammate roles | | ✓ |
| Manage billing or delete the project | | ✓ |
Editor is a fully trusted role. There is no separate Owner or Admin permission
tier: project creation does not give the creator protected permissions that
other Editors lack.
The server checks permissions for project, workflow, and workflow-run
operations. Hiding a control in the dashboard is not the only access check.
## Invite a teammate
From the project dashboard, open **Team**.
Select **Invite someone to your project**, enter their email address, and send
the invitation. The project must have an available seat.
The recipient follows the link in the invitation email. If they do not have a
WorkflowDog account, they must create one first. They must be signed in with
the exact email address that received the invitation.
New invitations currently join as **Editors**. If the teammate only needs
read access, change them to **Viewer** after they accept.
A pending invitation remains on the Team page until it is accepted or an
Editor cancels it. Sending a second invitation to the same address while one
is pending is not allowed.
## Change a role
Open a teammate's menu on the **Team** page and choose **Make Viewer** or
**Make Editor**.
Role changes take effect at the project boundary:
* A Viewer retains access to project data but loses write access.
* An Editor gains write access across workflows, variables, integrations,
billing, and team management.
* Roles in one project do not grant access to another project.
You cannot change your own role from your own member card. Ask another Editor
to change it.
## Remove a teammate
Choose **Remove from project** from the member's menu and confirm. Removal
revokes their project access; it does not delete workflows or other resources
they created.
To restore access later, send a new invitation.
## Manage seats
The Team page compares accepted members with the project's seat allowance.
Pending invitations do not replace an existing member. When the project has
reached its limit, use **Usage & Billing** or contact WorkflowDog about
additional team seats.
## Protect sensitive project data
Viewers can inspect variable values, run inputs and outputs, and connected
account metadata. Do not use project membership as a way to expose only one
workflow or only part of a workflow.
For the same reason:
* Do not store API keys or passwords in project variables.
* Review run outputs before inviting someone who should not see processed
customer data.
* Give Editor access only when the person should be able to alter or delete
project resources.
## Troubleshooting
Sign in with the exact email address that was invited. The invitation also
becomes invalid after an Editor cancels it or after it has already been
accepted.
You need Editor access and an available project seat. The invite also fails
when the email is already a member or already has a pending invitation.
This is expected. Viewer access is read-only at the API layer. Change the
teammate to Editor only if they should be able to modify the entire
project.
# Triggers
Source: https://learn.workflow.dog/essentials/triggers
Choose, configure, and use the event that starts a workflow.
A trigger defines the event that creates a workflow run. It may listen for an
email, expose an HTTP endpoint, watch a connected service, follow a schedule,
or allow another workflow to call this one.
Every workflow has exactly one trigger.
## Choose the trigger first
You select a trigger when creating a workflow. Choose the event that most
closely represents the boundary of the automation:
| Need | Trigger family |
| ------------------------------------- | ---------------------------------------- |
| Receive a request from another system | URL, Webhook, or Form Submission |
| React to a connected app | Gmail, Outlook, Google Forms, or TidyCal |
| Run repeatedly | Schedule |
| Start from an inbound email address | Email Hook |
| Reuse a workflow from another graph | Sub-Workflow |
The trigger type cannot be swapped in the editor. You can reopen and change its
configuration, but changing the kind of event requires another workflow.
See [Service triggers](/guides/service-triggers) for account-backed events,
[HTTP endpoints and webhooks](/guides/http-webhooks) for inbound requests, and
[Scheduling workflows](/guides/scheduling) for time-based automation.
## Configure the event source
Select the trigger button in the editor header to open its configuration.
Settings vary by trigger and may include:
* a connected account,
* a subject, label, form, or booking filter,
* one or more schedules and timezones, or
* a unique URL to copy into another system.
When you change a configurable trigger, use **Save** to apply it. **Reset**
discards the unsaved fields. Closing a dirty trigger panel also saves the
changes before it closes.
A broad trigger can create many runs. Configure the narrowest useful account,
source, and filter before enabling the workflow.
## Use trigger data
New workflows include a **Data from Trigger** node. On the canvas it takes the
name and color of the selected trigger, and its outputs match that trigger's
event payload.
For example:
* an email trigger exposes message and sender fields,
* a URL trigger exposes the method, path, headers, query, and body,
* a schedule exposes its timestamp, and
* a sub-workflow exposes the value passed as **Data In**.
Connect only the outputs the workflow needs. Object and list outputs may let you
select a property or pass the complete value.
The [Triggers reference](/reference/triggers) documents the exact outputs,
filters, request limits, and setup requirements for every trigger.
## Test with the real event
WorkflowDog does not currently provide a generic **Test Run** button. To get
representative trigger data, save the workflow, enable it, and cause the actual
event:
* send the matching email,
* submit the configured form,
* call the endpoint,
* create the booking, or
* wait for the configured schedule.
Then inspect the resulting run and its trigger outputs. Follow
[Testing workflows](/guides/testing-workflows) for the complete loop.
## Trigger configuration and workflow state
Trigger configuration decides which events match. Workflow state decides
whether matching events are accepted as new runs. A correctly configured but
paused workflow will not process new events.
See [Enable and pause](/essentials/enable-and-pause) for lifecycle behavior and
[Workflow runs](/essentials/workflow-runs) for observing what a trigger
created.
# Usage and billing
Source: https://learn.workflow.dog/essentials/usage-and-billing
Understand run credits, pay-as-you-go usage, seats, and billing failures.
Usage and billing are managed per project. A project's run credits are used
first; after they are gone, an active pay-as-you-go subscription allows
billable workflows to continue running.
The current pay-as-you-go rate shown in WorkflowDog is **$1 per 100 workflow
runs**, or **$0.01 per run**. A run can contain any number of actions.
## How a run is charged
When WorkflowDog receives a billable run:
1. It checks whether the workflow is Live.
2. It uses one project run credit when a credit is available.
3. If no credits remain, it checks for an active project subscription.
4. With valid usage billing, it records a \$0.01 usage charge.
5. Without valid billing, it marks the run Failed instead of executing it.
New projects currently begin with 100 introductory workflow-run credits. The
current balance appears under **Usage & Billing**.
The **Callable Workflow** trigger does not consume a credit or create a usage
charge. It is the current free trigger type. The Usage page can still include
free and failed runs in activity counts even when they contribute no cost.
## Credits before pay-as-you-go
Run credits are always depleted before paid usage accrues. Connecting a
subscription does not discard the remaining balance.
When a project has neither credits nor usable pay-as-you-go billing, billable
runs fail with:
```text theme={null}
The project is out of workflow runs and isn't set up for usage billing.
```
Enable billing, then send a new trigger event or
[re-run](/essentials/workflow-runs#re-run-with-the-same-trigger-data) a saved
payload. The failed run is not resumed automatically.
## What counts as a run
Billing eligibility is decided when the run is queued, before its nodes
execute. Therefore:
* A run that later completes with a node error still consumes its reserved
credit or paid usage.
* A run that fails the initial Paused, out-of-credit, or invalid-payment check
does not execute nodes.
* A Scheduled run reserves its credit or usage when it is scheduled.
* Cancelling a Scheduled run restores its credit or reverses its usage charge.
* The number of actions in the graph does not change the per-run price.
A Completed run can contain node errors and still be billable. Use the cost
card for billed usage and run history for execution quality; the raw run count
is not the same as the bill.
## Enable pay-as-you-go
Choose the project, then open **Usage & Billing** from the dashboard.
Check **Workflow Run Credits**, the current billing period, and recent usage
by workflow.
Select the upgrade option and complete the hosted checkout. Billing belongs to
this project only.
Return to the project and confirm the billing warning is gone. Live
billable workflows can now continue after credits reach zero.
Only an Editor can start checkout or open the billing-management portal.
## Read the Usage & Billing page
The page includes:
| Section | Meaning |
| ------------------------- | ---------------------------------------------------------------------- |
| **Usage Cost** | Sum of paid run charges in the selected billing period. |
| **Workflow Run Credits** | Prepaid or introductory runs remaining before paid usage accrues. |
| **Team Members** | Accepted project members compared with the project's seat allowance. |
| **Breakdown by Workflow** | Run activity attributed to each workflow, including deleted workflows. |
Use the period arrows to inspect an earlier billing period. A future period
cannot be selected.
Deleted workflows can remain in the breakdown because project-level run
records are preserved for usage tracking.
## Manage the subscription
When the project has an active subscription, **Manage** opens the billing
portal. Use it to update the payment method or subscription.
If WorkflowDog cannot accrue new usage, the project shows a billing warning and
new billable runs fail with:
```text theme={null}
The payment is invalid.
```
Fix the payment issue in the billing portal. Existing failed runs remain in
history; send a new event or re-run them after billing is healthy.
## Team seats
Seats are also tracked per project. When accepted members reach the seat
allowance, Editors cannot send another invitation.
Removing a member frees a seat. For a larger team plan, use the contact link
shown on **Usage & Billing**.
## Troubleshooting
Activity counts can include free Callable Workflow runs and runs that
failed before billing. Use **Usage Cost** for the amount accrued, not the
total activity count alone.
Credits and usage are reserved when the run is accepted, before node
execution. A node-level error does not refund the run automatically.
Cancellation restores a credit-backed run or records a negative usage
adjustment for a paid run. The history row remains with Cancelled status.
Open the billing portal and resolve the payment issue. A subscription
identifier alone is not enough; the project must also be allowed to accrue
usage.
# Project variables
Source: https://learn.workflow.dog/essentials/variables
Persist values between workflow runs and share them across a project.
**Project variables** store values between workflow runs. Every workflow in the
same project can read or update a variable by its key.
Use project variables for state that must outlive one run, such as the last
processed identifier, a routing preference, or a list accumulated over time.
Project variables are not secrets. Every project member with Viewer or Editor
access can inspect their values from the dashboard. Do not store passwords,
API keys, or access tokens in them.
## Set and read a value
Add [Set Project Variable](/reference/actions/core/set-project-var).
Provide a **Key** and the **Value** to store. Setting an existing key
replaces its previous value.
In the same or another workflow, add [Get Project
Variable](/reference/actions/core/get-project-var) and use the exact same key.
Set **Default Value** when the workflow needs a fallback. Without a default, a
missing variable returns `null`.
Open **Variables** in the project dashboard to view the stored key, value,
and last update time.
## Variable behavior
| Operation | Existing key | Missing key |
| ---------- | --------------------------------------------------- | ------------------------------ |
| **Set** | Replaces the stored value. | Creates the variable. |
| **Get** | Returns the stored value with its WorkflowDog type. | Returns the default or `null`. |
| **Append** | Adds items when the current value is a list. | Starts with an empty list. |
| **Clear** | Deletes the variable record. | Makes no change. |
Keys are scoped to the project and matched exactly. `lastCustomerId` and
`LastCustomerId` are different variables.
The Variables dashboard search helps locate similar keys, but it does not
change exact key matching inside workflows.
## Append to a stored list
[Append to List in Project Variables](/reference/actions/core/append-to-project-var-list)
loads the current list, appends the supplied values in order, and stores the
combined list.
If the key does not exist, the action starts from `[]`. If the existing value
is not a list, the node reports **Value is not a list**. A value that can no
longer be decoded reports **Variable is corrupted**.
Append reads the existing list and writes a replacement; it is not an atomic
concurrent append. If parallel runs append to the same key at nearly the same
time, both can read the same old list and the later write can overwrite the
other run's additions. Serialize those writes or give parallel work separate
keys.
## Inspect and clear variables
Open **Variables** from the project dashboard to:
* Search keys.
* Preview simple values.
* Expand lists and objects in the data navigator.
* See when a value was last updated.
* Choose **Clear Value** to delete a variable.
The dashboard does not create or edit values directly. Use workflow actions to
set or append values.
Clearing a variable deletes it rather than storing `null`. The next **Get
Project Variable** returns its configured default, or `null` if no default was
set.
## Example: remember the last processed item
1. Start the workflow with a schedule trigger.
2. Get the `last_processed_id` project variable.
3. Fetch and process items created after that ID.
4. Set `last_processed_id` to the newest successfully processed item.
Set the variable only after the workflow successfully processes the item you
want to mark. If a node earlier in the path errors and the Set node does not
run, the previous checkpoint remains available for the next run.
## Choose stable keys
Good keys state both the value and its purpose:
```text theme={null}
support_last_processed_message_id
daily_report_recipient
crm_pending_record_ids
```
Avoid reusing one key for unrelated data types. A key that sometimes contains
a number and sometimes a list makes downstream workflows harder to reason
about and can break list-specific actions.
## Troubleshooting
Confirm the key matches exactly, including capitalization and whitespace,
and that the workflow is in the same project as the variable. Also check
whether someone cleared the value from the Variables page.
The key currently contains another type. Inspect it on the Variables page,
then clear it or use **Set Project Variable** to initialize it with a list.
Multiple runs are replacing the same list concurrently. Route updates through
one sequential workflow, avoid parallel execution for that key, or store each
run under a separate key.
The dashboard is for inspection and clearing. Add **Set Project Variable**
to a workflow to create or replace the value.
# Workflow runs
Source: https://learn.workflow.dog/essentials/workflow-runs
Inspect run history, understand statuses, replay inputs, and cancel scheduled work.
A **workflow run** is one execution attempt created from trigger data. Each run
stores its input payload, status, node outputs and errors, and a snapshot of the
workflow graph selected when the run was queued.
## Open run history
WorkflowDog provides two views:
| View | Best for |
| --------------------------- | ---------------------------------------------------------------- |
| **Project → Workflow Runs** | Reviewing activity across every workflow in a project. |
| **Editor → Run History** | Inspecting runs and node-level results for the current workflow. |
Both views update active **Pending** and **Running** rows automatically.
The project view shows the workflow name, date, duration, status, and run
actions. The editor history lets you select a run and display its data directly
on the canvas.
## Run statuses
| Status | Meaning |
| ------------- | ---------------------------------------------------------------------------- |
| **Pending** | Accepted and waiting for execution to start. |
| **Scheduled** | Accepted for a future time and waiting in the queue. |
| **Running** | The workflow runner has started processing the graph. |
| **Completed** | The runner finished the graph. One or more individual nodes may still error. |
| **Failed** | The run could not execute or the workflow runner itself failed. |
| **Cancelled** | An Editor cancelled the run while it was still Scheduled. |
**Completed** does not mean every node succeeded. A completed run with an
amber warning icon contains one or more node errors. Open the run and inspect
the affected nodes.
Common run-level **Failed** reasons include:
* The workflow was paused.
* The project had no remaining run credits and no active usage billing.
* The project's payment state did not allow new usage.
* The execution worker encountered an unrecoverable error.
See [Troubleshoot workflow runs](/guides/troubleshooting-runs) for a diagnostic
flow.
## Inspect a run on the canvas
Select a row from **Run History** in the workflow editor. Node outputs and
errors become available for that run, and the editor offers two canvas modes.
Shows the saved graph snapshot associated with the run. Use this mode to
answer: “What graph actually ran?”
The snapshot cannot be edited. It remains stable even after you change the
current workflow.
Keeps the current workflow graph editable while applying the selected run's
results where node and handle identifiers still match.
Use this mode to fix the current workflow while referring to a recent run.
If nodes were deleted, replaced, or rewired after the run, some historical
results may not line up with the current graph.
Use **Newer** and **Older** to move between the runs loaded by the editor. This
navigation operates on the latest 100 runs fetched for the workflow. Open the
history drawer and scroll when you need an older entry.
## Star an important run
Use the star action to mark an incident, representative payload, or run you
want to find again. Stars are stored with the run and are visible to project
members.
Starring does not change retention, execution, or billing.
## Re-run with the same trigger data
Choose **Re-run** to queue a new run using the selected run's saved trigger
payload.
A re-run is not an exact replay of the historical snapshot. It uses the same
trigger data against the workflow's **current saved graph**, then creates a
new snapshot for that graph. Review unsaved changes and wait for **Saved**
before re-running.
A re-run can also fail immediately when the workflow is paused, the project is
out of credits, or billing is invalid. It creates a separate history entry and
does not modify the original run.
## Cancel a scheduled run
Only a run in **Scheduled** status can be cancelled. Choose **Cancel Run** from
its actions.
Cancellation:
* Changes the run to **Cancelled**.
* Prevents the delayed execution from starting.
* Restores the run credit or usage charge reserved when the run was scheduled.
Pending and Running runs cannot be cancelled from the dashboard.
## Run history after deletion
Deleting a workflow removes its workflow graph, trigger configuration, event
sources, and snapshots. Project-level run records remain for usage tracking and
appear as **Deleted Workflow**.
A preserved run row from a deleted workflow cannot be re-run, and its
historical canvas snapshot is no longer available. Deleting the entire project
removes its run history.
WorkflowDog currently does not expose a configurable run-history retention
setting in the dashboard.
## Troubleshooting
The workflow runner completed, but at least one node reported an error.
Select the run, inspect the red or warning-marked nodes, and read their
stored error messages.
This is expected. Re-run preserves the old trigger payload, not the old graph.
Use **Snapshot (Read-Only)** to inspect the original graph and **Overlay** to
repair the current one.
Cancellation is limited to Scheduled runs. A Pending or Running run has
already moved beyond the cancellable delayed state.
The snapshot can be unavailable if its workflow was deleted. Check the
project-wide history for a **Deleted Workflow** label.
# Workflows
Source: https://learn.workflow.dog/essentials/workflows
Understand the graph, editing model, and execution rules behind every WorkflowDog automation.
A workflow turns one incoming event into a graph of actions. Its trigger
decides **when** a run begins, its actions decide **what** happens, and its
connections decide which values and dependencies move through the graph.
Unlike a checklist, a workflow does not run from top to bottom. Position on the
canvas is only for readability. The connections between nodes determine
execution order.
## Anatomy of a workflow
| Part | Purpose |
| --------------------- | ------------------------------------------------------------------------ |
| **Trigger** | Creates a run when its configured event occurs. |
| **Data from Trigger** | Exposes the event's fields as outputs on the canvas. |
| **Action** | Performs work, transforms data, or controls part of the run. |
| **Connection** | Passes an output into an input and creates a dependency between actions. |
| **Static input** | Supplies a fixed value from an action's configuration. |
Every workflow has one trigger. You choose it when creating the workflow, then
configure it from the trigger button in the editor header. If you need a
different kind of trigger, create another workflow and move or recreate the
relevant actions there.
## Build on the canvas
Create a workflow from the project's **Workflows** page and choose the event
that should start it. The new graph includes **Data from Trigger**,
displayed with the selected trigger's name and outputs.
Press /, ⌘ K, or ⌘ P to open action search.
Select an action to add it near the center of the canvas.
Select an action to open its configuration panel. Enter fixed values there,
or connect values from other nodes to its inputs.
Drag from an output handle to an input handle. A connected action waits for
that upstream value before it can run.
Graph changes save automatically. Check the header for **Saved** before
sending a test event, closing the page, or relying on the new version.
See [Actions](/essentials/actions) for node configuration and
[Triggers](/essentials/triggers) for choosing and configuring the event source.
## How the graph runs
When a trigger creates a run, WorkflowDog starts every action whose
dependencies are ready. This has several consequences:
* Actions on independent branches can run at the same time.
* An action with two connected inputs waits for both upstream values.
* A fixed value does not add an upstream dependency.
* Moving a node left, right, above, or below another node does not change
execution order.
* A circular set of dependencies is invalid and cannot be saved.
For example, if **Fetch Customer** and **Fetch Orders** both depend only on
trigger data, they can run concurrently. An action connected to both waits
until both branches resolve.
If one action must wait for another without consuming its value, add the
**Wait For** meta control. Conditions and error-handling outputs are covered
in [Meta controls](/building/meta-controls).
## What happens when a branch stops
Connections carry execution signals as well as values. If an upstream action
is disabled, skipped by a condition, or fails, its normal outputs do not
produce values. Actions that require those outputs do not run.
Other branches that do not depend on the stopped action can still finish. This
is why a run can complete with one or more action errors rather than failing as
one indivisible transaction.
Use the action's **Did Action Succeed?**, **Error**, and related meta outputs
when another branch should react to that outcome. See
[Meta controls](/building/meta-controls) for the complete pattern.
## Edit safely
WorkflowDog keeps a short local undo history while you edit:
* ⌘ Z undoes the latest graph change.
* ⌘ Y or ⌘ ⇧ Z redoes it.
* Selecting multiple nodes exposes alignment, layout, enable/disable,
duplicate, and deletion tools.
* Automatic layout is available from the editor toolbar.
Each run keeps a snapshot of the workflow graph it started with. Editing the
workflow affects future runs, not the historical graph attached to an existing
run. Learn how those snapshots appear in
[Workflow runs](/essentials/workflow-runs).
## Next steps
Once the graph is ready, [test it with a real trigger event](/guides/testing-workflows).
Then use [Enable and pause](/essentials/enable-and-pause) to control whether it
accepts new events.
# HTTP endpoints and webhooks
Source: https://learn.workflow.dog/guides/http-webhooks
Receive requests with URL, Webhook, or Form Submission triggers and return a response.
HTTP triggers give a workflow a unique public endpoint. Choose the trigger
based on the request shape you control:
| Trigger | Accepted request | Body and data | Best for |
| ------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------- |
| **URL** | Common methods including `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` | Text up to 10 MB; binary bodies become base64 strings | General HTTP integrations and custom clients |
| **Webhook** | `POST` only | Parsed JSON up to 100 MB | Services that send JSON webhooks |
| **Form Submission** | `GET` or `POST` | Query fields on `GET`; multipart fields and files on `POST` | Browser forms, Webflow, Framer, and file forms |
Open the trigger configuration to copy its endpoint. Treat this URL like an
unguessable integration address: share it only with the systems that should
start the workflow.
## URL trigger
Use **URL** when you need control over the request method or body type. Its
trigger data includes:
* **Path**
* **Method**
* **Headers**
* **Query**
* **Body**
Header names are lowercase. Cookie, Cloudflare-prefixed, and forwarded-address
headers are omitted. Query values are exposed as strings. Text bodies remain
text; binary bodies are exposed as base64 text.
The URL shown in the trigger panel can be opened directly for a quick `GET`
test.
## Webhook trigger
Use **Webhook** for an external service that sends a JSON `POST`. Its trigger
data includes:
* **Data** — the parsed JSON value,
* **Path**,
* **Query**, and
* **Headers**.
Requests with another method receive `405 Method Not Allowed`. Invalid JSON is
rejected before the workflow receives trigger data.
## Form Submission trigger
Use **Form Submission** as an HTML form's target. A `POST` parses multipart form
fields and files. Repeated field or file names may produce lists rather than
single values.
The trigger can also serve configured HTML on `GET`. When **HTML Response** is
enabled, opening the endpoint returns that HTML and does **not** create a
workflow run. A `POST` to the same endpoint still submits the form and starts
the workflow.
If the HTML response is disabled, a `GET` starts the workflow with its query
parameters exposed as **Fields**.
## Return a custom response
Add one response action to the branch that should answer the caller. **Respond
Text**, **Respond JSON**, **Respond Status**, and **Redirect** are available for
all three HTTP triggers. The browser-oriented **Respond HTML**, **Respond
File**, and **Close Window** actions are intended for URL and Form Submission
workflows.
Connect every value that must be computed before the response. The HTTP request
waits for a response-capable action when an enabled one exists anywhere in the
run's graph snapshot.
Only the first response action that executes can answer the request. If
several response branches are eligible concurrently, their canvas position
does not decide which wins. Make the branches mutually exclusive or route them
into one response action.
## Default response behavior
The caller receives different defaults depending on the saved graph:
| Workflow outcome | HTTP result |
| --------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| No enabled response-capable action exists in the run snapshot | Immediate `202` explaining that the workflow is running without a response |
| A response action exists and runs | Its configured status, headers, and body |
| A response action exists, but the workflow completes without using it | `200` explaining that the workflow finished without a response |
| The run cannot be queued or fails at the worker level | `400` with the workflow failure message |
An action error does not automatically become an HTTP error response. A
dependent response action may be skipped because the failed action produced no
normal output, which leads to the generic completed-without-response result.
Use **Did Action Succeed?** and **Error** to build an explicit error response
branch.
See [Meta controls](/building/meta-controls) for that pattern.
## Test the endpoint
Save the graph, enable the workflow, and send a representative request. For
repeatable testing, keep an example `curl` command or request fixture with the
method, headers, query, and body your integration actually sends.
Then inspect both sides:
1. Confirm the caller received the expected status, headers, and body.
2. Open the workflow run and inspect **Data from Trigger**.
3. Check any decoded object properties, files, or base64 body before passing
them downstream.
Follow [Testing workflows](/guides/testing-workflows) for the full edit-test
loop and [External triggers](/essentials/external-triggers) for other ways
systems can start workflows.
# Scheduling workflows
Source: https://learn.workflow.dog/guides/scheduling
Choose between recurring schedules and one-time delayed sub-workflow runs.
WorkflowDog has two different scheduling tools:
| Goal | Use |
| --------------------------------------------------- | ----------------------------------------------------- |
| Run this workflow repeatedly | **Schedule** trigger |
| Run another workflow once at a future date and time | **Schedule Workflow** action with a callable workflow |
They are not interchangeable. The trigger owns recurring automation for its
current workflow. The action queues one child run and continues without
waiting for that child to execute.
## Create a recurring schedule
Choose **Schedule** when creating the workflow, then open its trigger
configuration.
Select **Add Schedule**. A new schedule starts at 9:00 AM every day in your
browser's current timezone.
Set an exact time or interval, then narrow it by day of month, day of week,
or month. Presets include Hourly, Daily, Daily at 9 AM, Weekdays at 9 AM,
and Monthly.
Choose the IANA timezone that should own the wall-clock time. The schedule
follows that timezone through daylight-saving changes.
Save the trigger configuration, wait for the graph to show **Saved**, and
make the workflow live when it is ready.
A workflow can contain multiple recurring schedules. Each recurrence-and-timezone
pair must be unique. Every event exposes a **Timestamp** through **Data from
Trigger**.
The timestamp records when the scheduled event was emitted. Queue load or
retries can make the run begin slightly later.
## Schedule a one-time child run
Use **Schedule Workflow** inside a parent workflow when an event should queue
follow-up work for one specific future time.
The selected child must use the **Sub-Workflow** trigger. Configure:
* **Selected Workflow** — the callable child to run,
* **Date & Time** — at least 10 seconds in the future, and
* **Payload** — optional data exposed as **Data In** inside the child.
The action queues the child and has no result output. It does not wait until the
scheduled date and does not wait for the child to complete. Use
[Run Workflow](/reference/actions/core/run-workflow) instead when the parent
needs the child's returned result immediately.
The child workflow must be enabled when **Schedule Workflow** queues it.
Pausing the child later does not cancel a delayed run that is already
scheduled. Cancel that run from workflow runs if it should no longer execute.
The delayed run captures the child's graph snapshot when it is queued. Later
edits apply to newly queued runs, not that already scheduled run.
Learn the complete callable-workflow pattern in
[Sub-workflows](/building/sub-workflows).
## Choose a timezone deliberately
Recurring schedules store an explicit timezone. Use the timezone of the
business event, not necessarily the timezone of the person configuring it. For
example, a daily storefront report should normally follow the storefront's
zone.
A connected **Date & Time** value for **Schedule Workflow** represents one
specific instant. If you build that value from text, include or intentionally
convert its timezone before scheduling it.
## Verify scheduled work
Scheduled runs appear with a scheduled status before they start. Use
[Workflow runs](/essentials/workflow-runs) to inspect or cancel them.
There is no generic Test Run button for schedules. For a recurring workflow,
temporarily add a near-future schedule, enable the workflow, wait for one event,
and remove the temporary recurrence after verification. Do not leave a
high-frequency test schedule attached to a live workflow.
# Service triggers
Source: https://learn.workflow.dog/guides/service-triggers
Start workflows from Gmail, Outlook, Google Forms, and TidyCal events.
Service triggers watch an account in another product and create a workflow run
when a matching event arrives. Configure the account and filters in the
trigger panel; configure downstream service actions separately on their own
nodes.
## Available service events
| Service | Trigger | Configurable scope |
| ------------ | -------------------- | ------------------------------------------------------------------------- |
| Gmail | New Email | Google account and case-sensitive subject text |
| Gmail | Sent Email | Google account, case-sensitive subject text, and automated email behavior |
| Gmail | Label Added to Email | Google account and optional case-insensitive label name |
| Outlook | New Email | Microsoft account and case-sensitive subject text |
| Google Forms | Google Form Response | Google account and the form's editing URL |
| TidyCal | New TidyCal Booking | TidyCal account |
See the [Triggers reference](/reference/triggers) for the exact output fields
from each event.
## Configure an account-backed trigger
Select the trigger while creating the workflow. The editor opens its
configuration automatically when setup is required.
Choose a healthy account with the permissions required by that trigger. You
can connect a new account directly from the selector.
Add the available subject or label filter, or select the exact form. Start
narrow; a broad inbox event can create many runs.
Select **Save** and wait for the confirmation. WorkflowDog creates or
updates the service watcher behind the trigger.
Enable the workflow, then cause the event in the connected service. Inspect
the resulting run before widening the filter.
Account selection is project-scoped. The selector can use a healthy compatible
default account automatically, but the saved trigger still monitors the
specific account shown in its configuration.
Use [Integrations](/essentials/integrations) to set defaults, reconnect an
unhealthy account, see where an account is used, or replace it across nodes.
## Email filters and loops
Gmail and Outlook subject filters match when the subject includes the entered
text. The comparison is case-sensitive. Leave the field blank to accept every
email for that event.
The Gmail label trigger's label filter is case-insensitive. It reports labels
that were newly added; it is not a query for all messages that already carry
the label.
By default, Gmail's **Sent Email** trigger ignores messages sent by
WorkflowDog automations. Enabling **Trigger on automated emails?** includes
them and can create an infinite loop if the workflow also sends email from the
same account.
Before allowing automated sent emails, draw the loop end to end. Add a strict
filter or condition that guarantees an email produced by the workflow cannot
trigger the same path indefinitely.
## Form and booking events
For **Google Form Response**, paste the form URL shown while editing the form,
not a response spreadsheet or unrelated sharing URL. Trigger data includes the
response ID, respondent email when available, answers grouped by question, and
quiz score when available.
**New TidyCal Booking** monitors the selected account for newly created,
non-cancelled bookings. It checks for new bookings on a one-minute interval, so
a matching event may not appear immediately. Its outputs include booking time,
timezone, contact details, meeting URL, booking type, and question answers.
## Test and troubleshoot
There is no generic Test Run button. After the trigger is saved and the
workflow is enabled, create a new matching event in the provider.
If no run appears, verify:
* the workflow is live,
* the trigger panel shows the intended account,
* the account is healthy and has the requested permissions,
* capitalization matches a subject filter,
* the label or form is the one the event actually used, and
* enough time has passed for a polled service such as TidyCal.
Continue with [Testing workflows](/guides/testing-workflows) and
[Troubleshooting runs](/guides/troubleshooting-runs). For inbound URLs,
webhooks, forms hosted by WorkflowDog, and email hooks, see
[External triggers](/essentials/external-triggers).
# Testing workflows
Source: https://learn.workflow.dog/guides/testing-workflows
Test a workflow with representative trigger data and verify each branch.
Testing a workflow means sending a real event through its configured trigger,
then inspecting what each action received and produced. WorkflowDog does not
currently have a generic **Test Run** button.
## The test loop
Finish the change, save any open trigger configuration, and wait until the
editor header says **Saved!**. Sending an event earlier can start a run from
the previous graph.
A paused workflow does not accept new trigger events. Follow [Enable and
pause](/essentials/enable-and-pause) if the workflow is not live.
Cause the event the trigger is designed to receive. Use realistic values,
including optional fields and attachments that matter to the automation.
Open the workflow's runs, select the new run, and inspect trigger data,
action outputs, and node errors.
Deselect the historical run, edit the current graph, wait for **Saved**, and
send another event. Compare the new result with the expected outcome.
## Send the right event
| Trigger | Useful test event |
| -------------------- | ----------------------------------------------------------------------- |
| URL | Open its URL for a `GET`, or send the exact method and body you expect. |
| Webhook | Send a `POST` with representative JSON. |
| Form Submission | Submit the actual form, including a file if the workflow handles files. |
| Gmail or Outlook | Send an email that matches the configured subject or label filter. |
| Google Form Response | Submit the configured Google Form. |
| TidyCal booking | Create a real test booking. |
| Schedule | Temporarily use a near-future recurrence and wait for it to fire. |
| Sub-Workflow | Run it from a parent workflow with a representative **Payload**. |
For HTTP request formats and response behavior, see
[HTTP endpoints and webhooks](/guides/http-webhooks). For provider account and
filter setup, see [Service triggers](/guides/service-triggers).
## Inspect more than the final result
A correct final value can hide a broken branch that happened not to affect this
event. Check:
* the **Data from Trigger** outputs,
* each action that should have run,
* values on output handles,
* node-level errors,
* branches intentionally skipped by conditions, and
* side effects in the destination service.
Actions on independent branches can run concurrently. Do not use their visual
left-to-right order as evidence that one finished before the other. Add a data
connection or **Wait For** dependency when order matters.
Historical runs keep the graph snapshot used when they started. Use that
snapshot to understand an old result; use the current graph for the next test.
See [Workflow runs](/essentials/workflow-runs) and
[Troubleshooting runs](/guides/troubleshooting-runs) for the detailed
inspection workflow.
## Reuse an event after the first test
After you have one representative run, **Rerun** can reuse its trigger payload
against the workflow's current saved graph. This is useful when repeatedly
tuning transformations or branch logic.
Rerun repeats the stored trigger data; it does not recreate the external
event. It may repeat side effects such as sending messages, creating rows, or
calling APIs. Disable or isolate destructive actions before using it as a
tight test loop.
## Test the unhappy paths
Before relying on the workflow, send cases that exercise its boundaries:
* a missing optional field,
* an empty list,
* a value in the wrong format,
* a false condition,
* an expired or disconnected service account, and
* a downstream service error.
An action error stops dependent actions from receiving its normal outputs, but
independent branches can continue. Use
[Meta controls](/building/meta-controls) when the workflow should recover,
report, or clean up after a failed action.
# Troubleshoot workflow runs
Source: https://learn.workflow.dog/guides/troubleshooting-runs
Find the cause of failed runs and node errors, fix the current workflow, and test safely.
Start with the run's status and error location. A run-level **Failed** status
and a node error inside a **Completed** run describe different problems and
need different fixes.
## Diagnose the run
Open **Workflow Runs** from the project, or open **Run History** inside the
workflow editor and select the affected run.
If the run is **Failed**, read the status tooltip for its run-level reason. If
it is **Completed** with an amber warning, inspect the nodes that stored
errors.
Use **Snapshot (Read-Only)** to inspect the graph that actually executed. Do
not assume the current canvas still matches an older run.
Open the failed node's error and review upstream outputs. Confirm the input
shape, account, identifiers, and values the node received.
Switch to **Overlay** or deselect the run, make the correction, and wait until
the editor says **Saved**.
Choose **Re-run** to use the same trigger data with the current saved graph,
or send a new representative trigger event.
## Run-level failures
Run-level failures occur before node processing begins or when the workflow
runner itself cannot complete its job.
| Message or code | What to check |
| --------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| **The workflow is paused.** | Enable the workflow, then create a new run. |
| **The project is out of workflow runs and isn't set up for usage billing.** | Add credits or enable pay-as-you-go billing. |
| **The payment is invalid.** | Resolve the project's payment issue in the billing portal. |
| **The worker encountered an error.** | Re-run once; if it repeats, preserve the run ID and contact support. |
A failed eligibility check is not retried automatically. Fix the cause, then
send a new event or choose **Re-run**.
A manual re-run goes through the same Live/Paused and billing checks as an
external trigger event.
## Node errors in a Completed run
WorkflowDog records node errors independently and continues settling the graph.
The overall run can reach **Completed** even when one or more nodes failed.
Check:
* The failed node's exact stored message.
* Whether its connected inputs produced values.
* Whether a required static input is empty.
* Whether an integration account is healthy and has the required permission.
* Whether an external identifier still exists and belongs to that account.
* Whether the value's type matches what the node accepts.
Downstream nodes may not run when their required input path did not receive a
value from the failed node. Diagnose the earliest error in the path first.
## Inspect the graph that actually ran
This is the authoritative historical graph. Use it to confirm the node
version, connections, static values, disabled nodes, and layout selected
when the run was queued.
This applies historical results to the current editable graph where IDs
still match. Use it while implementing a fix, but switch back to Snapshot
when you need to verify historical structure.
If the workflow was deleted, the project can retain a **Deleted Workflow** run
row for usage tracking while its snapshot is no longer available.
## Re-run safely
Re-run copies the old run's trigger payload into a new run. It does not execute
the old graph.
Before re-running:
* Confirm the editor shows **Saved**.
* Confirm the workflow is Live.
* Confirm integration accounts are healthy.
* Consider whether the workflow sends messages, charges payments, creates
records, or performs another non-idempotent action.
* Check whether the original run partially completed before its node error.
Re-running can repeat side effects that succeeded in the original run. A node
error later in the graph does not roll back earlier emails, records, uploads,
or provider changes.
For risky workflows, temporarily disable side-effect nodes or route the payload
through a test copy before replaying it.
## Integration errors
When an account-backed node errors:
Open **Integrations** and look for **Needs Reconnecting**.
Open the node's account selector. Reauthorize the account if credentials are
invalid or the node says required permissions are missing.
Unhealthy or insufficiently scoped accounts can be cleared automatically from
the node. Select the healthy account again.
Confirm IDs, mailbox folders, labels, files, bases, tables, and other
external resources still exist and are accessible to that account.
For a trigger that stopped delivering events, continue with
[External triggers](/essentials/external-triggers#troubleshooting).
## Variable errors
For project variable problems:
* A missing key returns its default or `null`; it is not a run-level failure.
* Key matching is exact and project-scoped.
* Appending requires the existing value to be a list.
* Parallel append operations can overwrite one another because each operation
reads and replaces the list.
* Viewers can inspect values but only Editors can clear them.
Inspect the current value under **Project → Variables** before changing the
workflow.
## Scheduled runs
A Scheduled run can be cancelled before execution. Pending and Running runs
cannot be cancelled from the dashboard.
If a delayed run executed after the workflow was paused, it was already
accepted and scheduled before the pause. Pausing does not purge the delayed
queue.
## Save failures
The workflow editor shows **Waiting to save**, **Saving**, **Saved**, or
**Failed to save**.
Do not test a change until the status reaches **Saved**. WorkflowDog prevents
normal navigation while a save is still pending, but a failed save means the
current graph may not be on the server.
A graph containing a circular dependency is rejected during save. Remove the
cycle and wait for a successful save before re-running.
## Escalate a repeatable worker failure
When **The worker encountered an error** repeats with the same saved graph and
payload:
1. Star the representative run.
2. Record the workflow name, run date and time, and run ID from its URL or
request data.
3. Note whether a new trigger event and a manual re-run fail the same way.
4. Contact WorkflowDog support without copying secrets into the message.
The stored run gives support the execution context; the external account's
credentials should never be pasted into a ticket.
## Quick symptom guide
Verify the external trigger configuration, provider permissions, and
account health. Then send a new matching event. A trigger filter mismatch
can prevent WorkflowDog from producing a run.
Read the run-level failure tooltip. Paused and billing failures happen before
node execution.
Look for an amber warning and inspect the earliest node error. Downstream
nodes may not receive a signal after an upstream failure.
Compare the saved trigger payload with the new event. Re-run preserves the
old payload, which may reference an external resource that no longer exists
or contain a value your new event does not.
# Welcome to WorkflowDog
Source: https://learn.workflow.dog/introduction
Build automations by connecting triggers, actions, and data.
WorkflowDog is a visual automation builder. A workflow starts with one
**trigger**, passes data through connected **actions**, and records the result
as a **run**.
You can use workflows to receive webhooks, process email, update spreadsheets,
call APIs, generate files, schedule work, run AI models, and connect those
operations into one automation.
Create a live HTTP endpoint and inspect its first run.
Learn how triggers, actions, dependencies, and runs fit together.
Add an external account, review its permissions, and see where it is used.
Open the complete action and trigger reference.
## The core model
### Projects contain your automation system
A project is the boundary around workflows, connected accounts, persistent
variables, team access, run history, and billing. Data and accounts are scoped
to a project, so choose the project before creating or connecting anything.
### A trigger starts each workflow
Every workflow has one trigger. It might receive an HTTP request, observe a new
email or form response, run on a schedule, or accept a call from another
workflow.
The trigger provides the first values in the graph. An incoming HTTP request,
for example, can expose its method, path, query parameters, headers, body, and
uploaded files.
### Actions run when their dependencies are ready
Actions are nodes on the editor canvas. Connections carry values from outputs
to inputs and establish execution dependencies.
A workflow is not read from left to right or top to bottom. An action runs
when the values it depends on are ready. Independent branches can run at the
same time.
### Every execution becomes a run
A run records the trigger data, status, node outputs, and node errors for one
execution. Use Run History to understand what happened, inspect a historical
snapshot, and rerun with the same trigger payload after making a change.
## A practical learning path
Follow the [Quickstart](/quickstart) to receive a URL request, build a
message, and return an HTTP response.
Read [Connect data](/building/connect-data) before building larger graphs.
It explains static and dynamic inputs, connections, lists, objects, and
required values.
Use [Meta controls](/building/meta-controls),
[branching](/building/branching), [lists and
loops](/building/lists-and-loops), and
[sub-workflows](/building/sub-workflows) as the automation grows.
Use [Testing workflows](/guides/testing-workflows) and [Run
History](/essentials/workflow-runs) to inspect actual inputs, outputs, and
errors.
Understand [Live and Paused workflows](/essentials/enable-and-pause),
account health, project variables, usage, and external-trigger lifecycle
before relying on the automation in production.
## Find exact node behavior
Guides explain how to design and operate automations. The reference documents
the exact inputs, outputs, defaults, limits, and caveats of each node:
* [Actions reference](/reference/actions)
* [Triggers reference](/reference/triggers)
The action picker also links directly to the matching reference page.
# Quickstart
Source: https://learn.workflow.dog/quickstart
Build and run a live HTTP workflow in a few minutes.
Build a workflow that receives a browser request and responds with a message
containing the request method and path.
The finished URL returns a message such as:
```text theme={null}
Hello! You made a GET request to /.
```
## Before you begin
Sign in at [workflow.dog/login](https://workflow.dog/login). A new account starts
with a project. If you already have several projects, select the one where this
workflow should live.
## 1. Create a workflow
Open **Workflows**, select **Create a Workflow**, and choose:
**HTTP → When a request is received at a URL**
WorkflowDog creates the workflow and opens its editor. The trigger panel shows
the public URL assigned to this workflow.
A workflow has one trigger. The trigger is chosen during creation, while
actions are added on the canvas afterward.
## 2. Add a Text action
Press / or select **Search actions** in the bottom toolbar. Search
for **Text**, then choose:
**Core → Text**
Enter this template in the action:
```handlebars theme={null}
Hello! You made a {{method}} request to {{path}}.
```
The Text action detects `method` and `path` and creates a dynamic input for
each one.
## 3. Connect the trigger data
The workflow includes **Trigger Data**, which exposes values from the incoming
request.
Create these two connections:
| From | To |
| ------------------------- | ----------------- |
| **Trigger Data → Method** | **Text → method** |
| **Trigger Data → Path** | **Text → path** |
Drag from an output handle to its matching input handle. A connection carries
the value and makes the Text action wait for that trigger output.
If a handle is hard to find, select the node to read its field descriptions in
the configuration panel.
## 4. Return the message
Open the action search again and choose:
**HTTP → Respond Text**
Connect:
| From | To |
| --------------- | ----------------------- |
| **Text → Text** | **Respond Text → Body** |
The response action sends the generated text back to the browser request that
started the workflow.
## 5. Wait for the workflow to save
WorkflowDog saves graph changes automatically. Watch the status beside the
workflow name and wait for **Saved!** before triggering a run.
Triggering while the editor still says **Saving...** can run the previous
saved graph.
## 6. Enable the workflow
Open the **Paused** menu and choose **Enable Workflow**. The status changes to
**Live**.
New workflows begin paused. While paused, incoming events do not wait to be
processed later; they produce failed runs. See
[Live and Paused workflows](/essentials/enable-and-pause) for the full
behavior.
## 7. Send a request
Open the trigger panel at the top-left of the editor and select **Go to URL**.
The page should display:
```text theme={null}
Hello! You made a GET request to /.
```
Add a path or query string to the URL and reload to create another run.
## 8. Inspect the run
Open **Run History** from the top-right of the editor. Select the latest run,
then inspect the graph:
* Trigger Data contains the HTTP method and path.
* Text shows the rendered output.
* Respond Text shows the response body it sent.
Use **Snapshot (Read-Only)** when you need the graph exactly as it existed for
that run. Learn more in [Workflow runs](/essentials/workflow-runs).
## What you learned
You have used the complete automation lifecycle:
1. A trigger received an event.
2. Connections carried event values into an action.
3. An action produced a new value.
4. A response action completed the HTTP request.
5. Run History recorded the execution.
Continue with [Connect data](/building/connect-data), or browse the exact
[URL trigger](/reference/triggers/http/url),
[Text action](/reference/actions/core/text), and
[Respond Text action](/reference/actions/http/respond) behavior.
# Route Incoming Email
Source: https://learn.workflow.dog/recipes/email-routing
Classify an incoming message and send it down the right workflow branch.
Email routing combines a service trigger with deterministic filters, optional
AI classification, and one branch per destination.
A typical workflow normalizes each new message, classifies it or applies fixed
rules, chooses a branch, then labels, drafts, forwards, replies, or notifies as
appropriate.
## Start with the narrowest trigger
Use a Gmail or Outlook new-email trigger and configure its built-in filters
when possible. Trigger filters avoid creating runs for messages the automation
will never process.
Remember that subject matching can be case-sensitive. Test with the exact
capitalization and message shapes that arrive in the real mailbox.
## Choose deterministic or AI routing
Use deterministic text and logic actions when the rule can be stated exactly:
* sender domain equals a known customer or vendor,
* subject starts with a fixed prefix,
* a label is present,
* body contains a specific identifier.
Use [OpenAI Chat](/reference/actions/openai/chat) with structured output when
the distinction depends on meaning rather than a fixed phrase. Keep the schema
small:
```json theme={null}
{
"type": "object",
"properties": {
"route": {
"type": "string",
"enum": ["sales", "support", "billing", "ignore"]
},
"summary": { "type": "string" },
"urgent": { "type": "boolean" }
},
"required": ["route", "summary", "urgent"],
"additionalProperties": false
}
```
Put hard safety rules before AI classification. For example, ignore your own
automated senders and known newsletters before paying to classify the
remaining messages.
## Build the branches
Connect `route` to a case-selection action or compare it in separate branches:
* `sales` can forward to the sales queue.
* `support` can add a label and draft a reply.
* `billing` can notify the billing team with the summary.
* `ignore` can end without a side effect.
Use [Conditional](/building/meta-controls) on side-effect actions so only the
matching branch runs. Independent preparation branches can still run
concurrently.
## Avoid mail loops
A workflow that sends, forwards, or labels mail can trigger another
email-based workflow—including itself. Filter automated senders, dedicated
labels, or recognizable headers so generated messages do not loop.
Before enabling:
1. Send representative messages for every route.
2. Confirm the trigger data contains the body and attachments you expect.
3. Inspect drafts before switching to automatic replies.
4. Test the fallback branch for ambiguous messages.
5. Review Run History for node errors even when a run status says completed.
See [Service event triggers](/guides/service-triggers) for account and event
lifecycle behavior.
# Build an HTTP Endpoint
Source: https://learn.workflow.dog/recipes/http-endpoint
Receive an HTTP request, process its data, and return a controlled response.
Use an HTTP-triggered workflow when another application needs to call your
automation through a URL.
Start with a URL, Webhook, or Form trigger; validate and transform the request
data; perform the work; then return text, JSON, HTML, a file, a status, or a
redirect.
## Choose the trigger
| Trigger | Use it for | Request data |
| ------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------------- |
| [URL](/reference/triggers/http/url) | General endpoints that accept common HTTP methods and text or binary bodies | Path, method, query, headers, body |
| [Webhook](/reference/triggers/http/webhook) | Services that send a JSON `POST` webhook | Path, headers, parsed JSON body |
| [Form](/reference/triggers/http/form) | Browser form submissions and optional hosted form HTML | Path, method, query, fields, files |
The trigger is selected when you create the workflow. If the upstream service
has a documented webhook format, use **Webhook**. Use **URL** for a custom API
surface and **Form** for browser-submitted fields or uploads.
## Validate the incoming data
Trigger Data exposes the request values. Treat all of them as untrusted.
* Check required properties before using them.
* Use type checks and conversion actions when a value may arrive as text.
* Validate structured bodies with
[Validate JSON Schema](/reference/actions/utilities/validate-json-schema).
* Return a clear `4xx` response when the request cannot be processed.
Do not place secrets in query parameters. URLs are commonly stored in browser,
proxy, and service logs. Prefer a request header or body field when the
sending service supports it.
## Return one response
Add the response action that matches the endpoint contract:
| Response action | Result |
| -------------------------------------------------------- | ------------------------------------- |
| [Respond Text](/reference/actions/http/respond) | Plain text with a configurable status |
| [Respond JSON](/reference/actions/http/respond-json) | A JSON response body |
| [Respond HTML](/reference/actions/http/respond-html) | Rendered HTML |
| [Respond File](/reference/actions/http/respond-file) | A downloadable or inline file |
| [Respond Status](/reference/actions/http/respond-status) | Status code without a body |
| [Redirect](/reference/actions/http/redirect) | Redirect to another URL |
Only response actions compatible with the selected trigger can be added. If
several branches can respond, design them so one branch wins for each request.
## Example: create a JSON endpoint
1. Create a workflow with the **Webhook** trigger.
2. Read the parsed body from Trigger Data.
3. Validate the required fields.
4. Run the actions that process the request.
5. Build a result object.
6. Connect it to **Respond JSON**.
7. Wait for **Saved!**, enable the workflow, and send a representative `POST`.
8. Inspect the run and the caller's response.
For an error branch, connect the validation result to a condition and return:
```json theme={null}
{
"ok": false,
"error": "email is required"
}
```
with status `400`. The success branch can return status `200` or `201`.
## Operate the endpoint
* Keep the workflow **Live** while callers depend on it.
* Watch [Run History](/essentials/workflow-runs) for failed requests and node
errors.
* Preserve a stable response shape when downstream applications parse it.
* If you pause the workflow, new requests produce paused-workflow failures;
they are not queued for later.
See [HTTP and webhook triggers](/guides/http-webhooks) for payload limits,
response timing, and the differences between the three trigger types.
# Build a Scheduled Automation
Source: https://learn.workflow.dog/recipes/scheduled-automation
Run a workflow repeatedly or queue another workflow for a future time.
WorkflowDog supports two scheduling patterns:
| Pattern | Use |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| [Schedule trigger](/reference/triggers/core/schedule) | Start this workflow on one or more recurring schedules. |
| [Schedule Workflow action](/reference/actions/core/schedule-workflow) | Queue a separate callable workflow to run once at a future date and time. |
Choose the trigger for recurring jobs such as a daily report. Choose the action
for delayed work such as sending a follow-up two days after an event.
## Example: send a daily report
Create a workflow with the **Schedule** trigger. Each run loads the reporting
data, formats the summary, and sends the finished email or message.
Add a daily schedule at the intended local time and confirm its timezone. A
workflow can have multiple schedule entries.
Add the actions that read the source system. Keep unrelated reads on
independent branches when they can run concurrently.
Combine the values into text, HTML, a spreadsheet, or a file. Use a
sub-workflow when the same report logic is reused elsewhere.
Add the send action, wait for the graph to save, enable the workflow, and
inspect its next run in Run History.
## Example: schedule a one-time follow-up
Create a second workflow with the
[Callable trigger](/reference/triggers/core/callable). Give its trigger inputs
the values the follow-up needs.
In the first workflow:
1. Add **Schedule Workflow**.
2. Select the callable workflow.
3. Set the future date and time.
4. Connect the callable workflow's inputs.
The scheduled execution appears in Run History. It already exists in the
queue, so pausing the child workflow does not remove it. Cancel that scheduled
run from history when it should no longer execute.
A delayed run uses the child workflow's saved graph when it executes. Review
scheduled work before making incompatible changes to the child's expected
trigger data.
## Make schedules reliable
* State the timezone explicitly; do not assume every teammate or service uses
the same local time.
* Design recurring work to tolerate being retried manually.
* Avoid relying on one run's in-memory state. Store durable state in the
destination service or a [project variable](/essentials/variables).
* Add **Succeeded?** or **Error** meta outputs around critical delivery actions
when a recovery branch is useful.
See [Scheduling workflows](/guides/scheduling) for configuration details and
[Workflow runs](/essentials/workflow-runs) for cancel and rerun behavior.
# Use Structured AI Output
Source: https://learn.workflow.dog/recipes/structured-ai
Turn unstructured text or files into predictable fields for later actions.
AI responses are easiest to automate when the model returns a small,
schema-defined object instead of prose.
A typical workflow sends a message, document, or image to **OpenAI Chat** with
Structured Output enabled. The resulting typed properties can drive
conditions, storage, and service actions.
## Design the schema around decisions
Start from what later actions need. For an intake workflow, that might be:
```json theme={null}
{
"type": "object",
"properties": {
"summary": {
"type": "string",
"description": "One sentence describing the request"
},
"category": {
"type": "string",
"enum": ["question", "bug", "billing"]
},
"priority": {
"type": "string",
"enum": ["low", "normal", "high"]
},
"customerEmail": {
"type": ["string", "null"]
}
},
"required": ["summary", "category", "priority", "customerEmail"],
"additionalProperties": false
}
```
Use enums for values that control a branch. Use nullable fields when the source
may legitimately omit a value. Avoid collecting fields no downstream action
uses.
## Configure Chat
1. Add [OpenAI Chat](/reference/actions/openai/chat).
2. Connect the source text to **Prompt**.
3. Add images or PDFs under **Files** when the model must inspect them.
4. Turn on **Structured Output**.
5. Paste the JSON schema.
6. Expose the detected properties you need as outputs.
Enabling Structured Output replaces the normal text **Response** with
**Structured Response**. Review existing connections when changing this
setting.
## Route and validate
Connect enum outputs to conditions or case selection. Connect extracted text
only to actions that accept missing or nullable values when the schema permits
them.
For high-impact work, add deterministic validation after the model:
* check that an email address is valid,
* confirm a number is in the allowed range,
* require human review before sending or deleting,
* reject categories outside the schema,
* preserve the original source for audit and correction.
## Handle failure deliberately
Enable the Chat action's **Succeeded?** and **Error** meta outputs. Use them to
send failures to a recovery branch without treating invented fallback data as
real extraction.
A valid schema controls the response shape, not the truth of its contents.
Treat model-produced values as untrusted whenever they can spend money, modify
access, send external messages, or make irreversible changes.
Use [Files and structured data](/building/files-and-structured-data) for
downstream object and file handling, and
[Troubleshoot workflow runs](/guides/troubleshooting-runs) when a model or
provider request fails.
# Create Record
Source: https://learn.workflow.dog/reference/actions/airtable/create-record
Create one Airtable record, including file attachments.
The **Create Record** action adds one record to an Airtable table. Field names
map directly to Airtable columns, and File values are uploaded to attachment
fields after the record is created.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ----------------------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-write access to the base. |
| **Base ID** | String | Yes | Airtable base identifier, typically beginning with `app`. |
| **Table Name or ID** | String | Yes | Visible table name or ID, typically beginning with `tbl`. |
| **Fields** | Object | No | Field-name/value pairs for the new record. |
| **Type Cast?** | Boolean | No | Let Airtable convert values to field types. Defaults to on. |
Add a File or list of Files as a field value to upload attachments to that
field. The destination must be an Airtable attachment field.
## Outputs
| Output | Type | Description |
| ------------------ | ------ | ------------------------------------------------------ |
| **Record ID** | String | ID of the new Airtable record. |
| **Created Record** | Object | Fields returned by Airtable, including uploaded files. |
Store **Record ID** whenever the workflow may update, retrieve, or delete the
same record later.
## Troubleshooting
Confirm the field name exists and its Airtable type accepts the supplied
value. **Type Cast?** can convert common input forms but cannot repair every
incompatible value.
# Create Records
Source: https://learn.workflow.dog/reference/actions/airtable/create-records
Create multiple Airtable records, including file attachments.
The **Create Records** action adds a list of records to one Airtable table. It
automatically partitions the work into Airtable's 10-record API batches, so the
input list can contain more than ten records.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ----------------------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-write access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or Airtable table ID. |
| **Records** | List of objects | Yes | At least one record of field-name/value pairs. |
| **Type Cast?** | Boolean | No | Let Airtable convert values to field types. Defaults to on. |
File-valued fields are uploaded after each batch's records are created.
## Outputs
**Created Records** contains one item per input record, in batch order:
| Field | Type | Description |
| ------------- | ------ | --------------------------------------------------- |
| **Record ID** | String | ID assigned by Airtable. |
| **Fields** | Object | Created fields, including uploaded attachment data. |
A failure in a later batch does not undo records already created by earlier
API requests.
## Example
For a contact import, first normalize the source data into a list of Airtable
field-name/value objects and connect that list to **Records**. After creation,
repeat over **Created Records** and store each **Record ID** wherever the source
contact is tracked.
# Delete Records
Source: https://learn.workflow.dog/reference/actions/airtable/delete-records
Delete multiple records from an Airtable table.
The **Delete Records** action permanently deletes records by ID. It groups
larger lists into Airtable's 10-record delete batches.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | --------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-write access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or Airtable table ID. |
| **Record IDs** | List of strings | Yes | Airtable record IDs to delete. |
Record deletion is permanent and this action returns no output. A failure in a
later batch does not restore records deleted by earlier requests.
An empty Record IDs list performs no operation.
# Find Records
Source: https://learn.workflow.dog/reference/actions/airtable/find-records
Find Airtable records using structured field comparisons.
The **Find Records** action turns one or more field filters into an Airtable
formula. Records must satisfy every filter. Use it when you want typed controls
without writing Airtable formula syntax yourself.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | -------------------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-read access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or ID. |
| **Filters** | List of filters | Yes | Field comparisons joined with Airtable `AND(...)`. |
| **Sort Field** | String | No | Field used to order matches. |
| **Sort Direction** | `asc` or `desc` | No | Sort direction. Defaults to `asc`; used with Sort Field. |
Each filter includes **Field Name**, **Match Mode**, and, when needed, **Search
Value**.
### Match modes
| Mode | Airtable behavior |
| ----------------------------------- | ---------------------------------------------------- |
| **Equals** / **Does Not Equal** | Compare a field with text, number, or boolean input. |
| **Is Empty** / **Is Not Empty** | Compare with `BLANK()`. |
| **Contains** / **Does Not Contain** | Use Airtable's case-sensitive `FIND` function. |
| **Matches Regex** | Use `REGEX_MATCH`. |
| **Greater/Less Than** variants | Numeric comparisons. |
| **Is True** / **Is False** | Compare with Airtable booleans. |
| **Is Truthy** / **Is Falsy** | Combine blank and false checks. |
## Outputs
| Output | Type | Description |
| ----------- | --------------- | --------------------------------- |
| **Records** | List of objects | Fields for every matching record. |
| **Count** | Number | Number of records returned. |
The action requests at most 1,000 records. Output objects contain fields but
not Airtable record IDs.
## Example: active premium accounts
Add two filters:
* **Status** → **Equals** → `Active`
* **Plan Value** → **Greater Than or Equal** → `1000`
Then sort by **Plan Value** in descending order.
## Troubleshooting
The generated formula uses Airtable's `FIND` function, whose text matching
is case-sensitive.
Field names are inserted exactly as supplied. Confirm the spelling and
punctuation match Airtable.
# Find Records by Formula
Source: https://learn.workflow.dog/reference/actions/airtable/find-records-by-formula
Find Airtable records with a native Airtable filter formula.
The **Find Records by Formula** action passes a formula directly to Airtable and
returns the field objects for records where the formula is truthy.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | -------------------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-read access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or ID. |
| **Filter Formula** | String | Yes | Airtable formula used as `filterByFormula`. |
| **Sort Field** | String | No | Field used to order matches. |
| **Sort Direction** | `asc` or `desc` | No | Sort direction. Defaults to `asc`; used with Sort Field. |
Example:
```text theme={null}
AND({Status} = "Open", {Amount} > 1000)
```
## Outputs
| Output | Type | Description |
| ----------- | --------------- | ---------------------------- |
| **Records** | List of objects | Fields for matching records. |
| **Count** | Number | Number of matches returned. |
The action requests at most 1,000 matches and omits Airtable record IDs from
each output object.
## Troubleshooting
Test it in Airtable first. Field names with spaces need braces, text needs
quotes, and function names must follow Airtable formula syntax.
# Get Record
Source: https://learn.workflow.dog/reference/actions/airtable/get-record
Retrieve one Airtable record's fields by record ID.
The **Get Record** action loads one record from an Airtable table.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-read access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or Airtable table ID. |
| **Record ID** | String | Yes | Airtable record ID, usually starting `rec`. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | -------------------------------------------------- |
| **Record** | Object | Record fields keyed by their Airtable field names. |
The output contains the fields object, not the Record ID or creation time.
Keep the input ID if later steps need it.
# Get Table Schema
Source: https://learn.workflow.dog/reference/actions/airtable/get-table-schema
Retrieve Airtable table metadata and field definitions.
The **Get Table Schema** action reads a base's metadata, resolves one table by
name or ID, and returns its field definitions. It requires Airtable schema-read
permission rather than record-read permission.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ---------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with `schema.bases:read` access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Exact table name or Airtable table ID. |
## Outputs
| Output | Type | Description |
| -------------------- | -------------- | -------------------------------- |
| **Name** | String | Table name. |
| **Description** | String | Table description, when present. |
| **Primary Field ID** | String | ID of the table's primary field. |
| **Fields** | List of fields | Metadata for every table field. |
Each **Fields** item contains:
| Field | Type | Description |
| --------------- | ------ | -------------------------------- |
| **ID** | String | Airtable field ID. |
| **Name** | String | Visible field name. |
| **Type** | String | Airtable field type identifier. |
| **Description** | String | Field description, when present. |
## Example: validate dynamic mappings
Use **Fields** as the source for a repeat step, then compare each field's
**Name** and **Type** with the mapping your workflow expects. Continue to the
record creation or update step only after the required fields have been
confirmed.
## Troubleshooting
Matching uses the exact Airtable table ID or table name. Inspect the base
and verify the connected account can read its schema.
# Get All Records
Source: https://learn.workflow.dog/reference/actions/airtable/list-records
List Airtable records with optional view, formula, and sorting.
The **Get All Records** action reads records from an Airtable table, follows
offset pagination, and returns each record's fields. A view, formula, and
single-field sort can narrow or order the result.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | -------------------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-read access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or ID. |
| **View Name or ID** | String | No | Limit records to an Airtable view. |
| **Filter Formula** | String | No | Airtable formula that records must satisfy. |
| **Sort Field** | String | No | Field used to order results. |
| **Sort Direction** | `asc` or `desc` | No | Sort direction. Defaults to `asc`; used with Sort Field. |
View and formula filters are combined by Airtable when both are supplied.
Test formulas in Airtable before placing them in a workflow.
## Outputs
| Output | Type | Description |
| ----------- | --------------- | --------------------------------------- |
| **Records** | List of objects | Field objects for the returned records. |
| **Count** | Number | Number of returned records. |
The action requests at most 1,000 records and returns field objects without
their Airtable record IDs. Use a dedicated ID field when downstream work must
retain an identifier.
## Troubleshooting
**Sort Direction** is sent only when **Sort Field** is also provided. Check
that the field name exists in the table.
# Update Record
Source: https://learn.workflow.dog/reference/actions/airtable/update-record
Merge into or replace one Airtable record.
The **Update Record** action changes one Airtable record. Choose **Merge** to
touch only supplied fields or **Replace** to replace the record's field set.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------------- | -------- | ----------------------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-write access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or ID. |
| **Record ID** | String | Yes | Record to update. |
| **Fields** | Object | Yes | Field-name/value pairs to write. |
| **Update Method** | `merge` or `replace` | No | Update strategy. Defaults to `merge`. |
| **Type Cast?** | Boolean | No | Let Airtable convert values to field types. Defaults to on. |
Updates only the supplied regular fields. Existing omitted fields remain.
Replaces the record with the supplied regular fields. Omitted fields can be
cleared.
File or File-list values are uploaded to their attachment fields after the
regular-field update.
**Replace** is destructive to omitted fields. Use **Merge** unless clearing
the rest of the record is intentional.
This action changes the record and returns no output.
# Update Records
Source: https://learn.workflow.dog/reference/actions/airtable/update-records
Merge into or replace multiple Airtable records.
The **Update Records** action applies updates to multiple record IDs. It sends
updates in batches of ten and uploads file-valued fields after each batch.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------------- | -------- | --------------------------------------------------------- |
| **Third-party account** | Airtable account | Yes | Account with record-write access. |
| **Base ID** | String | Yes | Airtable base ID. |
| **Table Name or ID** | String | Yes | Table name or ID. |
| **Updates** | List of updates | Yes | Each item contains **Record ID** and a **Fields** object. |
| **Update Method** | `merge` or `replace` | No | Strategy applied to every update. Defaults to `merge`. |
| **Type Cast?** | Boolean | No | Let Airtable convert supplied values. Defaults to on. |
**Merge** preserves omitted fields. **Replace** can clear every field omitted
from each update object.
The action returns no output and is not transactional across batches. If a
later request fails, earlier record updates are not rolled back.
# Append to List
Source: https://learn.workflow.dog/reference/actions/arrays/append
Add one or more items to the end of a list.
**Append to List** preserves the existing order of a list, then adds each new
item at the end.
## Inputs
| Input | Type | Required | Description |
| --------- | -------------- | -------- | ------------------------------------ |
| **List** | List | No | The starting list. Defaults to `[]`. |
| **Items** | Repeatable any | No | Items to append, in the order shown. |
## Output
| Output | Type | Description |
| ---------- | ---- | --------------------------------------------- |
| **Result** | List | The original items followed by the new items. |
For example, appending `3` and `4` to `[1, 2]` returns `[1, 2, 3, 4]`.
# Create List
Source: https://learn.workflow.dog/reference/actions/arrays/build
Combine individual values into a new list.
**Create List** collects its repeatable item inputs into one list. Use it when
separate values need to travel through the workflow as a single collection.
## Inputs
| Input | Type | Required | Description |
| --------- | -------------- | -------- | -------------------------------------------------- |
| **Items** | Repeatable any | No | Values to include. The node starts with two slots. |
## Output
| Output | Type | Description |
| -------- | ---- | ----------------------------------------- |
| **List** | List | Every supplied item, in input-slot order. |
Add or remove item slots as needed. With no items, the action returns an empty
list.
# Chunk List
Source: https://learn.workflow.dog/reference/actions/arrays/chunk
Split a list into smaller lists of a fixed maximum size.
**Chunk List** divides a list from left to right. The final chunk can contain
fewer items than the requested size.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ------------------------------------------- |
| **List** | List | No | The list to split. Defaults to `[]`. |
| **Size** | Number | Yes | A positive whole number of items per chunk. |
## Output
| Output | Type | Description |
| ---------- | ------------- | ------------------------------------ |
| **Chunks** | List of lists | The chunks, in their original order. |
For example, chunking `[1, 2, 3, 4, 5]` with a size of `2` returns
`[[1, 2], [3, 4], [5]]`.
**Size** must be a whole number greater than zero.
# Empty List
Source: https://learn.workflow.dog/reference/actions/arrays/empty-array
Produce a list containing no items.
**Empty List** is a compact value node with no inputs.
## Output
| Output | Type | Description |
| -------- | ---- | -------------------- |
| **List** | List | An empty list: `[]`. |
Use it to initialize a list input or explicitly represent “no items.”
# Filter With Workflow
Source: https://learn.workflow.dog/reference/actions/arrays/filter-with-workflow
Keep the list items for which another workflow returns a truthy value.
**Filter With Workflow** runs a selected workflow once for each input item and
keeps the items whose run returns a truthy **Data Out** value.
## Quick start
Give the workflow a **Data In** input and return the decision through **Data
Out**. The decision is converted to true or false by truthiness.
Choose that workflow, then connect a list to **Payloads**.
Connect **Results** to the next action.
## Inputs
| Input | Type | Required | Description |
| --------------------- | -------- | -------- | --------------------------------------------- |
| **Selected Workflow** | Workflow | Yes | The workflow used to test each item. |
| **Payloads** | List | No | Items to test, up to 1,000. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ----------- | ---- | --------------------------------------------- |
| **Results** | List | Passing items in the same order as the input. |
The predicate runs sequentially. If any child workflow fails, this action
fails instead of returning a partial list.
The selected workflow receives the current item as **Data In**. Values such as
non-empty strings and non-zero numbers pass because the returned value is
evaluated by truthiness, not required to be a Boolean.
# Find With Workflow
Source: https://learn.workflow.dog/reference/actions/arrays/find-with-workflow
Return the first list item accepted by another workflow.
**Find With Workflow** tests items from the beginning of a list and stops as
soon as the selected workflow returns a truthy **Data Out** value.
## Inputs
| Input | Type | Required | Description |
| --------------------- | -------- | -------- | ----------------------------------------------- |
| **Selected Workflow** | Workflow | Yes | The workflow used to test each item. |
| **Payloads** | List | No | Items to search, up to 1,000. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ---------- | ---- | ------------------------------------------------- |
| **Result** | Any | The first matching item, or `null` if none match. |
The selected workflow receives each candidate as **Data In**. A failed child
run fails the action; later candidates are not tested after a match.
Use **Filter With Workflow** when you need every matching item. Use this
action when only the first match matters.
# Flatten List
Source: https://learn.workflow.dog/reference/actions/arrays/flatten
Combine nested lists into a single list.
**Flatten List** removes one level of nesting by default, or all nested levels
when deep flattening is enabled.
## Inputs
| Input | Type | Required | Description |
| -------- | ------- | -------- | -------------------------------------------- |
| **List** | List | No | The list to flatten. Defaults to `[]`. |
| **Deep** | Boolean | No | Flatten every nested level. Defaults to off. |
## Output
| Output | Type | Description |
| ------------- | ---- | ------------------- |
| **Flattened** | List | The flattened list. |
With **Deep** off, `[[1], [[2]]]` becomes `[1, [2]]`. With it on, the same
input becomes `[1, 2]`.
# Get First Item
Source: https://learn.workflow.dog/reference/actions/arrays/get-first-item
Return the item at the beginning of a list.
## Input
| Input | Type | Required | Description |
| -------- | ---- | -------- | ---------------------------------- |
| **List** | List | No | The source list. Defaults to `[]`. |
## Output
| Output | Type | Description |
| -------------- | ---- | -------------------------------------------- |
| **First Item** | Any | The first item, or `null` for an empty list. |
The input list is not changed.
# Get Items by Index
Source: https://learn.workflow.dog/reference/actions/arrays/get-items
Expose selected list positions as individual outputs.
**Get Items by Index** creates one output for each repeatable index input. List
positions start at zero.
## Inputs
| Input | Type | Required | Description |
| ----------- | ----------------- | -------- | ----------------------------------- |
| **List** | List | No | The source list. Defaults to `[]`. |
| **Indices** | Repeatable number | No | Whole-number positions to retrieve. |
## Outputs
Each **Index** slot creates a matching **Item at Index *n*** output. The output
keeps the identity of its input slot, so reordering or removing index slots
updates the corresponding outputs.
Negative indices count backward from the end: `-1` retrieves the last item.
An index outside the list produces no value for that output.
# Get Last Item
Source: https://learn.workflow.dog/reference/actions/arrays/get-last-item
Return the item at the end of a list.
## Input
| Input | Type | Required | Description |
| -------- | ---- | -------- | ---------------------------------- |
| **List** | List | No | The source list. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ------------- | ---- | ------------------------------------------- |
| **Last Item** | Any | The last item, or `null` for an empty list. |
The input list is not changed.
# Insert at Index
Source: https://learn.workflow.dog/reference/actions/arrays/insert-at-index
Insert one or more items at a chosen list position.
**Insert at Index** places new items at a zero-based position and returns the
resulting list.
## Inputs
| Input | Type | Required | Description |
| --------- | -------------- | -------- | ------------------------------------------- |
| **List** | List | No | The starting list. |
| **Items** | Repeatable any | No | Items to insert, in the order shown. |
| **Index** | Number | Yes | The zero-based position at which to insert. |
## Output
| Output | Type | Description |
| ---------- | ---- | --------------------------------- |
| **Result** | List | The list with the items inserted. |
For example, inserting `b` and `c` at index `1` in `[a, d]` produces
`[a, b, c, d]`.
This action is visible in the workflow editor, but the current server package
does not include a matching implementation.
# Is List?
Source: https://learn.workflow.dog/reference/actions/arrays/is-array
Check whether a value is a list.
## Input
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
## Output
| Output | Type | Description |
| ---------- | ------- | ----------------------------------------------- |
| **Result** | Boolean | `true` for a list; `false` for any other value. |
Objects, strings, and `null` are not lists.
# Join Lists
Source: https://learn.workflow.dog/reference/actions/arrays/join
Concatenate multiple lists into one.
**Join Lists** adds the contents of each input list to the result in order. It
removes only the outer list boundary; nested lists inside an input remain
nested.
## Input
| Input | Type | Required | Description |
| --------- | --------------- | -------- | ---------------------------------------------- |
| **Lists** | Repeatable list | No | Lists to join. The node starts with two slots. |
## Output
| Output | Type | Description |
| ---------- | ---- | ------------------------------------ |
| **Joined** | List | All input items in input-list order. |
Joining `[1, 2]`, `[]`, and `[3]` returns `[1, 2, 3]`.
# Get Length
Source: https://learn.workflow.dog/reference/actions/arrays/length
Count the number of items in a list.
## Input
| Input | Type | Required | Description |
| -------- | ---- | -------- | ------------------------------------ |
| **List** | List | No | The list to count. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ---------- | ------ | ------------------------------ |
| **Length** | Number | The number of top-level items. |
Nested lists count as one item each.
# List Contains
Source: https://learn.workflow.dog/reference/actions/arrays/list-contains
Check whether a list contains a value.
## Inputs
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------------------------- |
| **List** | List | No | The list to search. Defaults to `[]`. |
| **Value** | Any | No | The value to find. |
## Output
| Output | Type | Description |
| ---------- | ------- | ----------------------------------------- |
| **Result** | Boolean | `true` when the value occurs in the list. |
The comparison is exact. Objects and lists match only when they are the same
runtime value; two separate objects with identical properties do not match.
# Prepend to List
Source: https://learn.workflow.dog/reference/actions/arrays/prepend
Add one or more items to the beginning of a list.
**Prepend to List** puts the new items first, preserving the order of both the
new items and the original list.
## Inputs
| Input | Type | Required | Description |
| --------- | -------------- | -------- | ------------------------------ |
| **List** | List | No | The existing list. |
| **Items** | Repeatable any | No | Items to add at the beginning. |
## Output
| Output | Type | Description |
| ---------- | ---- | ----------------------------------- |
| **Result** | List | The new items followed by the list. |
For example, prepending `1` and `2` to `[3, 4]` produces `[1, 2, 3, 4]`.
This action is visible in the workflow editor, but the current server package
does not include a matching implementation.
# Create Range
Source: https://learn.workflow.dog/reference/actions/arrays/range
Create a regularly spaced list of numbers.
**Create Range** starts at one number and adds a step until it reaches the end
boundary.
## Inputs
| Input | Type | Required | Description |
| ------------- | ------- | -------- | ------------------------------------------ |
| **Start** | Number | No | First number. Defaults to `0`. |
| **End** | Number | Yes | End boundary. |
| **Step** | Number | No | Amount added per item. Defaults to `1`. |
| **Inclusive** | Boolean | No | Include the end boundary. Defaults to off. |
## Output
| Output | Type | Description |
| -------- | --------------- | ------------------------------- |
| **List** | List of numbers | Numbers in the generated range. |
With **Start** `0`, **End** `5`, and **Step** `2`, the result is `[0, 2, 4]`.
Turning on **Inclusive** adds one more stepped value.
Use a positive step for an end greater than the start and a negative step for
an end less than the start. A zero step or a step pointed away from the end
cannot produce a valid range. When **Inclusive** is on and the step does not
land exactly on **End**, the extra value can pass the end boundary.
# Repeat Elements
Source: https://learn.workflow.dog/reference/actions/arrays/repeat
Repeat a sequence of list items a chosen number of times.
## Inputs
| Input | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------------- |
| **Elements** | List | No | The sequence to repeat. Defaults to `[]`. |
| **Count** | Number | Yes | A non-negative whole number of repetitions. |
## Output
| Output | Type | Description |
| -------- | ---- | ---------------------------- |
| **List** | List | The repeated input sequence. |
For example, repeating `[a, b]` three times returns
`[a, b, a, b, a, b]`. A count of `0` returns an empty list.
# Reverse List
Source: https://learn.workflow.dog/reference/actions/arrays/reverse
Return a list with its item order reversed.
## Input
| Input | Type | Required | Description |
| -------- | ---- | -------- | ---------------------------------- |
| **List** | List | No | The source list. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ------------ | ---- | --------------------------------- |
| **Reversed** | List | A new list in the opposite order. |
`[a, b, c]` becomes `[c, b, a]`. The source list is not modified.
# Shuffle List
Source: https://learn.workflow.dog/reference/actions/arrays/shuffle
Randomly reorder the items in a list.
## Input
| Input | Type | Required | Description |
| -------- | ---- | -------- | ---------------------------------- |
| **List** | List | No | The source list. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ------------ | ---- | -------------------------------------- |
| **Shuffled** | List | A randomly reordered copy of the list. |
Every item appears exactly once, but the order may differ on each run. A
shuffle can occasionally return the original order, especially for short
lists.
# Slice List
Source: https://learn.workflow.dog/reference/actions/arrays/slice
Extract a section of a list by position.
**Slice List** returns items from the start index up to, but not including, the
end index.
## Inputs
| Input | Type | Required | Description |
| --------- | ------ | -------- | --------------------------------------------- |
| **List** | List | No | The source list. Defaults to `[]`. |
| **Start** | Number | No | Inclusive, zero-based start. Defaults to `0`. |
| **End** | Number | No | Exclusive end. Defaults to the list length. |
## Output
| Output | Type | Description |
| --------- | ---- | --------------------------------- |
| **Slice** | List | The selected portion of the list. |
For `[a, b, c, d]`, start `1` and end `3` return `[b, c]`.
Although the editor description mentions negative indices, the server
currently accepts only non-negative whole numbers for **Start** and **End**.
# Sort List
Source: https://learn.workflow.dog/reference/actions/arrays/sort
Sort numbers, strings, or object properties.
**Sort List** returns a sorted copy of the input. It can compare top-level
values or a nested property selected by an object path.
## Inputs
| Input | Type | Required | Description |
| --------------- | ------ | -------- | --------------------------------------------- |
| **List** | List | No | Values to sort. Defaults to `[]`. |
| **Direction** | String | Yes | **Ascending** (default) or **Descending**. |
| **Object Path** | String | No | Nested property such as `user.name` or `age`. |
## Output
| Output | Type | Description |
| ---------- | ---- | --------------------------- |
| **Sorted** | List | A sorted copy of the input. |
Numbers are compared numerically and strings use locale-aware text ordering.
When **Object Path** is set, those same rules apply to the value at that path.
Items whose compared values are not both numbers or both strings compare as
equal, so their relative positions are preserved.
# Get Unique Items
Source: https://learn.workflow.dog/reference/actions/arrays/unique
Remove duplicate values while keeping their first occurrence.
## Input
| Input | Type | Required | Description |
| -------- | ---- | -------- | ---------------------------------- |
| **List** | List | No | The source list. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ---------- | ---- | ----------------------------------- |
| **Unique** | List | The first occurrence of each value. |
Primitive values such as strings and numbers are deduplicated by value.
Objects and nested lists are duplicates only when they refer to the same
runtime value.
# Zip Lists
Source: https://learn.workflow.dog/reference/actions/arrays/zip
Combine matching positions from multiple lists.
**Zip Lists** groups the first item from every input list, then the second item
from every list, and so on. The result is as long as the longest input; missing
positions become `null`.
## Inputs
| Input | Type | Required | Description |
| ------------------------------- | --------------- | -------- | ------------------------------------------- |
| **Name Lists with Object Keys** | Boolean | No | Return objects instead of positional lists. |
| **Lists** | Repeatable list | No | Lists to combine. Starts with two slots. |
When naming is enabled, every list entry has a **Key** and **List** input. Each
output item is an object whose properties use those keys.
## Output
| Output | Type | Description |
| ---------- | ---- | --------------------------------------- |
| **Zipped** | List | Positionally combined lists or objects. |
Zipping `[1, 2]` and `["a"]` returns `[[1, "a"], [2, null]]`.
Naming the same lists `id` and `label` returns
`[{"id": 1, "label": "a"}, {"id": 2, "label": null}]`.
Toggling **Name Lists with Object Keys** replaces the list-input shape and
changes each output item from a list to an object. Check downstream
connections after changing it.
# Activate Email Template
Source: https://learn.workflow.dog/reference/actions/brevo/activate-email-template
Make an existing Brevo email template active.
**Activate Email Template** sets an existing Brevo template's active state to
true.
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | -------------------------------- |
| **Third-party account** | Brevo account | Yes | The API key used for the update. |
| **Template ID** | Positive number | Yes | The Brevo template to activate. |
The action has no output. Continue the workflow after Brevo confirms the
template was updated.
# Add Contacts to List
Source: https://learn.workflow.dog/reference/actions/brevo/add-contacts-to-list
Add existing Brevo contacts to a contact list by email.
**Add Contacts to List** adds one or more existing contacts to a Brevo contact
list. Brevo reports individual addresses that succeed or fail.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | --------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The Brevo account that owns the contact list. |
| **Contact List ID** | Number | Yes | The destination contact list. |
| **Emails** | List of emails | Yes | Existing Brevo contacts to add. |
## Outputs
| Output | Type | Description |
| --------------------- | -------------- | ----------------------------------------- |
| **Successful Emails** | List of emails | Contacts Brevo added to the list. |
| **Failed Emails** | List of emails | Contacts Brevo could not add to the list. |
This action does not create missing contacts. Use **Upsert Contact** before
this action when an address may not exist in Brevo.
# Create Email Template
Source: https://learn.workflow.dog/reference/actions/brevo/create-email-template
Create an HTML transactional email template in Brevo.
**Create Email Template** creates a reusable Brevo template with its sender,
subject, and HTML content.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------------- | -------- | ------------------------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The API key used to create the template. |
| **Template Name** | String | Yes | A non-empty name visible in Brevo. |
| **Subject** | String | Yes | A non-empty email subject. |
| **HTML Content** | String | Yes | A non-empty HTML body. |
| **Sender Email** | String | Yes | The address shown as the sender. |
| **Sender Name** | String | No | The display name shown with the sender address. |
| **Is Active** | Boolean | No | Whether the template can be used immediately. Defaults to on. |
## Output
| Output | Type | Description |
| --------------- | ------ | ------------------------- |
| **Template ID** | Number | The ID assigned by Brevo. |
Store **Template ID** if a later workflow will activate, deactivate, or send
from this template.
# Deactivate Email Template
Source: https://learn.workflow.dog/reference/actions/brevo/deactivate-email-template
Make an existing Brevo email template inactive.
**Deactivate Email Template** sets an existing Brevo template's active state to
false. The template remains in the account and can be activated again later.
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | --------------------------------- |
| **Third-party account** | Brevo account | Yes | The API key used for the update. |
| **Template ID** | Positive number | Yes | The Brevo template to deactivate. |
The action has no output.
# Get Contact Lists
Source: https://learn.workflow.dog/reference/actions/brevo/get-contact-lists
List contact lists in a Brevo account.
**Get Contact Lists** retrieves one page of contact lists from Brevo.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------------- | -------- | ------------------------------------------------ |
| **Third-party account** | Brevo account | Yes | The Brevo account to inspect. |
| **Limit** | Number | No | Lists to return, from 0 to 50. Defaults to 50. |
| **Offset** | Number | No | Lists to skip. Defaults to 0. |
| **Sort** | Choice | No | Sort by creation time. Defaults to newest first. |
## Outputs
| Output | Type | Description |
| --------- | --------------- | --------------------------------------------- |
| **Lists** | List of objects | The requested page of Brevo contact lists. |
| **Count** | Number | Total contact lists in the connected account. |
Each list exposes **List ID**, **Name**, **Folder ID**, and **Unique
Subscribers**.
If **Count** exceeds **Limit**, increase **Offset** in another action to
retrieve the next page.
# Get Sent Email Content
Source: https://learn.workflow.dog/reference/actions/brevo/get-email-content
Retrieve a sent Brevo transactional email by message ID.
**Get Sent Email Content** retrieves the recipient, subject, HTML body, and
timestamp for a previously sent transactional email.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------------- | -------- | ----------------------------------------------------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The account that sent the email. |
| **Message ID** | String | Yes | A Brevo message ID from a send action or email logs. A Brevo email UUID is also accepted. |
## Outputs
| Output | Type | Description |
| ---------------- | ------ | ---------------------------- |
| **Recipient** | String | The recipient email address. |
| **Subject** | String | The sent subject line. |
| **HTML Content** | String | The sent message body. |
| **Date** | Date | When the email was sent. |
When given a message ID rather than a UUID, WorkflowDog first looks up the
matching email record and then retrieves its content.
# Get Email Templates
Source: https://learn.workflow.dog/reference/actions/brevo/get-email-templates
List Brevo transactional email templates.
**Get Email Templates** retrieves up to 250 templates from a Brevo account.
## Inputs
| Input | Type | Required | Description |
| --------------------------------- | ------------- | -------- | ------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The account to inspect. |
| **Only Include Active Templates** | Boolean | No | Exclude inactive templates. Defaults to on. |
## Outputs
| Output | Type | Description |
| ------------- | --------------- | ------------------------------------- |
| **Templates** | List of objects | The returned templates. |
| **Count** | Number | Brevo's total count for the response. |
Each template exposes **Template ID**, **Template Name**, **Subject**, **Sender
Name**, **Sender Email**, **Reply To**, **Is Active**, **HTML Content**,
**Created At**, and **Modified At**.
The action requests a maximum of 250 templates. Accounts with more templates
may need narrower organization outside this action.
# Remove Contacts from List
Source: https://learn.workflow.dog/reference/actions/brevo/remove-contacts-from-list
Remove Brevo contacts from a contact list by email.
**Remove Contacts from List** removes one or more contacts from a Brevo contact
list. It does not delete the contacts from the Brevo account.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | --------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The Brevo account that owns the contact list. |
| **Contact List ID** | Number | Yes | The contact list to update. |
| **Emails** | List of emails | Yes | Contacts to remove from the list. |
## Outputs
| Output | Type | Description |
| --------------------- | -------------- | ---------------------------------------------- |
| **Successful Emails** | List of emails | Contacts Brevo removed from the list. |
| **Failed Emails** | List of emails | Contacts Brevo could not remove from the list. |
# Send Email from Template
Source: https://learn.workflow.dog/reference/actions/brevo/send-email-from-template
Send a Brevo transactional email from an existing template.
**Send Email from Template** uses a Brevo template and optional parameter
values to send to one or more recipients.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------------------------ | -------- | ----------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The API key used to send. |
| **Template ID** | Non-negative integer | Yes | The Brevo template to use. |
| **Recipients** | List of emails | Yes | One or more destination addresses. |
| **CC** | List of emails | No | Carbon-copy recipients. |
| **Parameters** | List of name/value pairs | No | Values made available to template placeholders. |
For a parameter named `FIRSTNAME`, use the following placeholder in Brevo:
```text theme={null}
{{params.FIRSTNAME}}
```
## Output
| Output | Type | Description |
| -------------- | ------ | -------------------------------- |
| **Message ID** | String | Brevo's identifier for the send. |
Keep parameter names stable and match their capitalization exactly between the
template and the workflow.
# Send Email
Source: https://learn.workflow.dog/reference/actions/brevo/send-transactional-email
Send a custom transactional email through Brevo.
Brevo **Send Email** sends custom HTML with an optional plain-text alternative,
CC recipients, reply-to address, and file or URL attachments.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | --------------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The API key used to send. |
| **Recipients** | List of emails | Yes | One or more destination addresses. |
| **CC** | List of emails | No | Carbon-copy recipients. |
| **Subject** | String | Yes | A non-empty subject line. |
| **HTML Content** | String | Yes | The HTML message body. |
| **Text Content** | String | No | A plain-text alternative. |
| **Sender Email** | String | Yes | The address shown as the sender. |
| **Sender Name** | String | No | The sender display name. |
| **Reply To** | String | No | The address that receives replies. |
| **Attachment Files** | List of files | No | Workflow files encoded and uploaded with the email. |
| **Attachment URLs** | List of URLs | No | Public files Brevo should fetch and attach. |
URL attachments use the last part of the URL path as their filename.
## Output
| Output | Type | Description |
| -------------- | ------ | -------------------------------- |
| **Message ID** | String | Brevo's identifier for the send. |
Supply **Text Content** for clients that cannot render HTML and for better
accessibility. Keep attachment URLs public for as long as Brevo needs to fetch
them.
# Send Transactional SMS
Source: https://learn.workflow.dog/reference/actions/brevo/send-transactional-sms
Send a non-promotional SMS message through Brevo.
**Send Transactional SMS** sends an operational text message such as a
confirmation, alert, or one-time code.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------------- | -------- | --------------------------------------------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The API key used to send. |
| **Recipient** | String | Yes | Phone number with country code and 6 to 15 digits. |
| **Sender** | String | Yes | Up to 11 letters or digits, or up to 15 digits. |
| **Content** | String | Yes | The text message to send. |
| **Tags** | List of text | No | Up to 10 Brevo reporting tags. |
| **Unicode Enabled** | Boolean | No | Enable accented characters, non-Latin scripts, and emoji. |
| **Organization Prefix** | String | No | A brand prefix added before the message; it counts toward the SMS segment length. |
| **Webhook URL** | URL | No | URL that receives Brevo delivery events for this message. |
## Output
| Output | Type | Description |
| -------------- | ------ | --------------------------------------- |
| **Message ID** | String | Brevo's identifier for the SMS request. |
Use this action only for transactional messages. Brevo automatically
reclassifies content containing an opt-out stop code as marketing SMS, which
can make the message subject to regional sending restrictions.
Message content plus the optional **Organization Prefix** counts toward the
160-character segment limit. Longer messages may be split and consume multiple
credits. Unicode messages can have a lower per-message character limit.
# Upsert Contact
Source: https://learn.workflow.dog/reference/actions/brevo/upsert-contact
Create or update a Brevo contact by email.
**Upsert Contact** creates a contact or updates the existing contact with the
same email address. It can set account-defined attributes, add the contact to
lists, and change email or SMS blocklist status.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------------- |
| **Third-party account** | Brevo account | Yes | The Brevo account that owns the contact. |
| **Email** | Email | Yes | The address that identifies the contact. |
| **Attributes** | Object | No | Account-defined contact attributes and their values. |
| **Contact List IDs** | List of numbers | No | Lists to add the contact to. |
| **Email Blocklisted** | Boolean | No | Block or allow marketing email for the contact when provided. |
| **SMS Blocklisted** | Boolean | No | Block or allow SMS messages for the contact when provided. |
## Output
| Output | Type | Description |
| -------------- | ------ | ------------------------------------------------------ |
| **Contact ID** | Number | Brevo's identifier for the created or updated contact. |
Attribute names must already exist in the connected Brevo account. Workflow
Dog converts them to uppercase before sending them, so `firstname` becomes
`FIRSTNAME`. Brevo may ignore values that do not match the configured
attribute type.
# Get Page Content
Source: https://learn.workflow.dog/reference/actions/cloudflare/content
Render a URL with Cloudflare Browser Rendering and return HTML, Markdown, JSON, or a PDF.
**Get Page Content** loads a public URL in a browser operated by Cloudflare and
returns the page in the format you choose. It is useful when a normal HTTP
request is not enough because the page depends on JavaScript.
## Inputs
| Input | Type | Required | Description |
| ----------------------------- | ------------------------------------ | -------- | --------------------------------------------------------------------------------------------- |
| **Third-party account** | Cloudflare account | Yes | The Cloudflare account and API credentials used for browser rendering. |
| **URL** | String | Yes | The complete page URL to render. |
| **Format** | `HTML`, `Markdown`, `JSON`, or `PDF` | Yes | Controls both the rendering endpoint and the node's output. Defaults to `HTML`. |
| **Prompt Or Schema** | String | No | For `JSON` only. A JSON schema or natural-language prompt that describes the data to extract. |
| **Wait For Selector** | String | No | A CSS selector that must appear before Cloudflare captures the result. |
| **Wait Time** | Number | No | Extra time to wait after the page loads, from `0` to `30000` milliseconds. |
| **Viewport Width** | Number | No | Browser viewport width, up to `1920`. Defaults to `1920`. |
| **Viewport Height** | Number | No | Browser viewport height, up to `1080`. Defaults to `1080`. |
| **JavaScript Code** | String | No | JavaScript inserted into the rendered page as a script. |
| **Additional API Parameters** | Object | No | Extra fields passed to Cloudflare's Browser Rendering API. |
When **Format** is `JSON`, the node first tries to parse **Prompt Or Schema** as
JSON. Valid JSON is sent as a JSON schema; any other string is sent as an
extraction prompt.
JavaScript Code runs inside the remote page. Only use code and input values
you trust, and do not place secrets in code that the page could read.
## Outputs
The selected format changes which output is available:
| Format | Output | Type | Description |
| ---------- | ------------ | ------ | --------------------------------------- |
| `HTML` | **Content** | String | Rendered page HTML. |
| `Markdown` | **Content** | String | Page content converted to Markdown. |
| `JSON` | **Data** | Object | Structured data returned by Cloudflare. |
| `PDF` | **PDF File** | File | A PDF named after the page's hostname. |
## Example: extract product data
Choose `JSON`, then set **Prompt Or Schema** to a schema such as:
```json theme={null}
{
"type": "object",
"properties": {
"name": { "type": "string" },
"price": { "type": "string" },
"inStock": { "type": "boolean" }
},
"required": ["name", "price"]
}
```
If the page renders its product card asynchronously, set **Wait For Selector**
to the product card's CSS selector before extracting it.
## Troubleshooting
Wait for a stable CSS selector, or add a short **Wait Time**. A selector is
usually more reliable than a fixed delay on pages with variable load times.
Confirm that **Prompt Or Schema** is valid JSON. If parsing fails, the node
treats the entire value as a natural-language prompt.
Match the page's expected viewport, then use **JavaScript Code** or
**Additional API Parameters** for site-specific browser behavior.
# HTML to PDF
Source: https://learn.workflow.dog/reference/actions/cloudflare/html-to-pdf
Render an HTML document as a PDF with Cloudflare Browser Rendering.
**HTML to PDF** renders an HTML string in Cloudflare's remote browser and
returns the result as a PDF file. Use it for invoices, reports, certificates,
and other documents assembled earlier in a workflow.
## Inputs
| Input | Type | Required | Description |
| ----------------------------- | ------------------ | -------- | --------------------------------------------------------------------- |
| **Third-party account** | Cloudflare account | Yes | The Cloudflare account used to render the document. |
| **HTML** | String | Yes | The complete HTML document or fragment to render. |
| **Wait For Selector** | String | No | A CSS selector that must appear before the PDF is captured. |
| **Wait Time** | Number | No | Extra time to wait after rendering, from `0` to `30000` milliseconds. |
| **Viewport Width** | Number | No | Browser viewport width, up to `1920`. Defaults to `1920`. |
| **Viewport Height** | Number | No | Browser viewport height, up to `1080`. Defaults to `1080`. |
| **JavaScript Code** | String | No | JavaScript inserted into the rendered document. |
| **Additional API Parameters** | Object | No | Extra Browser Rendering API fields, such as PDF-specific options. |
## Output
| Output | Type | Description |
| ------------ | ---- | --------------------------------- |
| **PDF File** | File | The rendered `page.pdf` document. |
Put print-specific rules in the HTML with `@media print`. Page size, margins,
headers, and footers can be supplied through **Additional API Parameters**
when supported by Cloudflare's PDF endpoint.
External stylesheets, fonts, and images must be reachable from Cloudflare's
browser. For the most portable document, use absolute URLs or embed the assets
directly in the HTML.
## Troubleshooting
Replace local and relative asset paths with public absolute URLs, or embed
the asset in the HTML. The remote browser cannot access files on your
computer or private network.
Set **Wait For Selector** to an element created after rendering finishes, or
add a small **Wait Time**.
# HTML to Screenshot
Source: https://learn.workflow.dog/reference/actions/cloudflare/html-to-screenshot
Render HTML and capture it as a PNG, JPEG, or WebP image.
**HTML to Screenshot** turns an HTML string into an image using Cloudflare
Browser Rendering. It can capture either the configured viewport or the full
height of the rendered document.
## Inputs
| Input | Type | Required | Description |
| ----------------------------- | ------------------------ | -------- | ------------------------------------------------------------------------- |
| **Third-party account** | Cloudflare account | Yes | The Cloudflare account used for rendering. |
| **HTML** | String | Yes | The HTML to render. |
| **Format** | `png`, `jpeg`, or `webp` | Yes | Image encoding. Defaults to `png`. |
| **Full Page** | Boolean | No | Captures the full document instead of only the viewport. Defaults to off. |
| **Wait For Selector** | String | No | A CSS selector that must appear before capture. |
| **Wait Time** | Number | No | Extra delay after load, from `0` to `30000` milliseconds. |
| **Viewport Width** | Number | No | Viewport width, up to `1920`. Defaults to `1920`. |
| **Viewport Height** | Number | No | Viewport height, up to `1080`. Defaults to `1080`. |
| **JavaScript Code** | String | No | JavaScript inserted into the rendered HTML before capture. |
| **Additional API Parameters** | Object | No | Extra fields passed to Cloudflare's screenshot endpoint. |
## Output
| Output | Type | Description |
| -------------- | ---- | -------------------------------------------------------------------------- |
| **Screenshot** | File | The captured image, named `rendered` with the selected format's extension. |
With **Full Page** off, viewport width and height define the capture area.
With it on, the width still affects responsive layout while the page height
expands to include the full document.
## Example: generate a social card
Build a fixed-size HTML card with inline CSS, select a `1200` by `630`
viewport, and leave **Full Page** off. Connect **Screenshot** to an upload,
email, or image-processing action.
## Troubleshooting
Change **Viewport Width** before capture. The viewport controls which CSS
media queries apply.
Enable **Full Page**, or increase **Viewport Height** when you intentionally
want a fixed-size capture.
# Get Links on Page
Source: https://learn.workflow.dog/reference/actions/cloudflare/links
Render a web page and return the links Cloudflare finds on it.
**Get Links on Page** opens a URL with Cloudflare Browser Rendering and returns
the links found after the page renders. This is useful for link discovery on
JavaScript-heavy pages.
## Inputs
| Input | Type | Required | Description |
| ----------------------------- | ------------------ | -------- | ----------------------------------------------------------- |
| **Third-party account** | Cloudflare account | Yes | The Cloudflare account used for browser rendering. |
| **URL** | String | Yes | The complete page URL to inspect. |
| **Wait For Selector** | String | No | A CSS selector that must appear before links are collected. |
| **Wait Time** | Number | No | Extra delay after load, from `0` to `30000` milliseconds. |
| **Viewport Width** | Number | No | Viewport width, up to `1920`. Defaults to `1920`. |
| **Viewport Height** | Number | No | Viewport height, up to `1080`. Defaults to `1080`. |
| **JavaScript Code** | String | No | JavaScript inserted into the rendered page. |
| **Additional API Parameters** | Object | No | Extra fields passed to Cloudflare's links endpoint. |
## Output
| Output | Type | Description |
| --------- | --------------- | --------------------------------------------------------------------------- |
| **Links** | List of strings | Links returned by the rendered page. The list is empty when none are found. |
This action discovers links on one page; it does not crawl those links. Use a
loop or a crawl-oriented integration when you need to visit them.
If links appear only after an interaction, use **JavaScript Code** to perform
that interaction and **Wait For Selector** to identify when the new content is
ready.
# Take Screenshot
Source: https://learn.workflow.dog/reference/actions/cloudflare/screenshot
Capture a rendered web page as a PNG, JPEG, or WebP image.
**Take Screenshot** opens a URL in Cloudflare's remote browser and captures the
rendered page. Unlike a direct HTTP request, it can wait for client-side
content and run JavaScript before capture.
## Inputs
| Input | Type | Required | Description |
| ----------------------------- | ------------------------ | -------- | -------------------------------------------------------------------------- |
| **Third-party account** | Cloudflare account | Yes | The Cloudflare account used for browser rendering. |
| **URL** | String | Yes | The complete page URL to capture. |
| **Format** | `png`, `jpeg`, or `webp` | Yes | Image encoding. Defaults to `png`. |
| **Full Page** | Boolean | No | Captures the full document rather than only the viewport. Defaults to off. |
| **Wait For Selector** | String | No | A CSS selector that must appear before capture. |
| **Wait Time** | Number | No | Extra delay after load, from `0` to `30000` milliseconds. |
| **Viewport Width** | Number | No | Viewport width, up to `1920`. Defaults to `1920`. |
| **Viewport Height** | Number | No | Viewport height, up to `1080`. Defaults to `1080`. |
| **JavaScript Code** | String | No | JavaScript inserted into the page before capture. |
| **Additional API Parameters** | Object | No | Extra fields passed to Cloudflare's screenshot endpoint. |
## Output
| Output | Type | Description |
| -------------- | ---- | -------------------------------------------------- |
| **Screenshot** | File | The captured image, named from the URL's hostname. |
## Example: capture a loaded dashboard
Set **URL** to the dashboard, **Wait For Selector** to a selector on its final
chart, and choose the viewport used by the dashboard's desktop layout. Turn on
**Full Page** when charts extend below the initial viewport.
Cloudflare must be able to reach and authenticate to the URL. Do not expect a
browser session from your own computer to be present in the remote browser.
## Troubleshooting
The remote browser does not share your local cookies. Use supported request
or browser parameters to authenticate only when it is safe to do so.
Wait for a selector that appears after the content loads. Use **Wait Time**
only when the page has no reliable ready-state element.
# Fallback
Source: https://learn.workflow.dog/reference/actions/control/coalesce
Choose the first usable value from an ordered set of alternatives.
**Fallback** checks its **Try** inputs from top to bottom and returns the first
one that qualifies under the selected mode.
## Inputs
| Input | Type | Required | Description |
| -------- | -------------- | -------- | ------------------------------------- |
| **Try** | Repeatable any | Yes | Candidate values, checked in order. |
| **Mode** | String | Yes | **Non-Null** (default) or **Truthy**. |
Skips only `null`. Values such as `false`, `0`, and empty text are valid
results.
Skips falsy values, including `null`, `false`, `0`, and empty text.
## Output
| Output | Type | Description |
| --------- | ---- | -------------------------------------- |
| **Value** | Any | The first qualifying value, or `null`. |
Use **Non-Null** for default values where `false` or `0` is meaningful. Use
**Truthy** only when those values should also fall through.
# Route Value
Source: https://learn.workflow.dog/reference/actions/control/demux
Send a value to one of two outputs based on a condition.
## Inputs
| Input | Type | Required | Description |
| ------------- | ------- | -------- | -------------------------- |
| **Value** | Any | Yes | The value to route. |
| **Condition** | Boolean | Yes | Selects the active output. |
## Outputs
| Output | Type | Description |
| ------------ | ---- | ----------------------------------------------- |
| **If True** | Any | Receives the value when the condition is true. |
| **If False** | Any | Receives the value when the condition is false. |
Only the selected output is produced during a run. Use **Choose Value** for
the inverse pattern: two possible inputs feeding one output.
# Is Falsy?
Source: https://learn.workflow.dog/reference/actions/control/is-falsy
Convert JavaScript-style falsiness into a Boolean result.
## Input
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
## Output
| Output | Type | Description |
| ---------- | ------- | ------------------------------- |
| **Result** | Boolean | `true` when the value is falsy. |
Falsy values include `null`, `false`, `0`, empty text, and missing values.
Empty lists and empty objects are truthy.
# Is Truthy?
Source: https://learn.workflow.dog/reference/actions/control/is-truthy
Convert JavaScript-style truthiness into a Boolean result.
## Input
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
## Output
| Output | Type | Description |
| ---------- | ------- | -------------------------------- |
| **Result** | Boolean | `true` when the value is truthy. |
`null`, `false`, `0`, empty text, and missing values are falsy. Empty lists
and empty objects are truthy.
# Choose Value
Source: https://learn.workflow.dog/reference/actions/control/mux
Choose between two values using a Boolean condition.
## Inputs
| Input | Type | Required | Description |
| ------------- | ------- | -------- | --------------------------------------- |
| **If True** | Any | No | Returned when the condition is `true`. |
| **If False** | Any | No | Returned when the condition is `false`. |
| **Condition** | Boolean | Yes | Selects which input to return. |
## Output
| Output | Type | Description |
| ---------- | ---- | ------------------- |
| **Result** | Any | The selected input. |
An unconnected selected input produces no value. Both alternatives may have
different data types, so check what downstream actions accept.
# Choose Value by Case
Source: https://learn.workflow.dog/reference/actions/control/mux-case
Map an exact text match to a corresponding output value.
**Choose Value by Case** compares text against a set of named cases and returns
the value belonging to the matching case.
## Inputs
| Input | Type | Required | Description |
| -------------- | ----------------- | -------- | -------------------------------------------------- |
| **Test Value** | String | Yes | Text to look up. |
| **Cases** | Repeatable object | Yes | One or more **Case** and **Value** pairs. |
| **Default** | Any | No | Returned when no case matches. Defaults to `null`. |
Each **Case** is a string key. Matching is exact and case-sensitive.
## Output
| Output | Type | Description |
| ---------- | ---- | ---------------------------------------- |
| **Result** | Any | The matching case value, or **Default**. |
For example, cases `urgent → page`, `normal → queue` and a test value of
`urgent` return `page`.
This action chooses a value. To send one value to separate workflow branches,
use **Route Value** after producing a Boolean condition.
# Passthrough
Source: https://learn.workflow.dog/reference/actions/control/passthrough
Expose an input unchanged as an output.
**Passthrough** is primarily useful while arranging or testing a workflow.
| Input | Type | Required | Description |
| --------- | ---- | -------- | -------------------------- |
| **Value** | Any | Yes | The value to pass through. |
| Output | Type | Description |
| --------- | ---- | ---------------------- |
| **Value** | Any | The exact input value. |
The action does not copy, convert, or validate the value.
# Third-Party Account
Source: https://learn.workflow.dog/reference/actions/core/account
Select a connected account and pass it to another action.
**Third-Party Account** creates a reusable account value. Use it when several
actions should use the same connected account, or when an account input needs
to be selected independently.
## Inputs
| Input | Type | Required | Description |
| ----------- | ------- | --------- | ------------------------------------ |
| **Service** | Service | Yes | The integration provider. |
| **Account** | Account | Sometimes | Appears after a service is selected. |
## Output
| Output | Type | Description |
| ----------- | ------- | -------------------------------------- |
| **Account** | Account | The selected account for that service. |
The available services come from the integrations installed in WorkflowDog.
The server verifies that the selected account belongs to the chosen service.
Changing **Service** changes the account type. Select a new account and check
downstream connections after switching providers.
# Append to List in Project Variables
Source: https://learn.workflow.dog/reference/actions/core/append-to-project-var-list
Add values to a project-wide persistent list.
**Append to List in Project Variables** loads a stored list, adds the supplied
values to its end, and saves the result under the same key. If the key does not
exist, the action starts with an empty list.
## Inputs
| Input | Type | Required | Description |
| ---------- | -------------- | -------- | -------------------------------------- |
| **Key** | String | Yes | Name of the project variable. |
| **Values** | Repeatable any | Yes | One or more values to append in order. |
The action has no output. Use **Get Project Variable** afterward when the
updated list is needed in the workflow.
The existing value must be a list. The action fails with `Value is not a list`
for another type, or `Variable is corrupted` when the stored value cannot be
read.
The value is shared by every workflow in the project. Simultaneous
read-and-append operations can overwrite one another, so this action is not a
transactional queue.
# True/False
Source: https://learn.workflow.dog/reference/actions/core/boolean
Provide a fixed Boolean value.
Use the switch on the compact **True/False** node to choose a value. It defaults
to off.
| Input | Type | Required | Description |
| ----------- | ------- | -------- | ----------------------------- |
| **Boolean** | Boolean | No | On is `true`; off is `false`. |
| Output | Type | Description |
| ------ | ------- | ------------------------- |
| | Boolean | The current switch value. |
# Comment
Source: https://learn.workflow.dog/reference/actions/core/comment
Add explanatory Markdown to the workflow canvas.
**Comment** is purely visual. It does not produce data or affect execution.
## Settings
| Setting | Options | Default |
| -------------- | -------------------- | ------- |
| **Text** | Markdown text | Empty |
| **Text Align** | Left, Center, Right | Center |
| **Text Size** | Small, Medium, Large | Small |
Use comments to explain assumptions, label sections, or leave maintenance
notes beside related actions.
Anyone who can view the workflow can read the comment. Do not put secrets or
credentials in it.
# Convert Encoding
Source: https://learn.workflow.dog/reference/actions/core/convert-encoding
Decode text from one byte encoding and encode it as another.
**Convert Encoding** first interprets **Input Text** using its declared source
encoding, then emits the same bytes in the target encoding.
## Inputs
| Input | Type | Required | Description |
| ------------------- | ------ | -------- | --------------------------------------------- |
| **Input Text** | String | Yes | Text or encoded byte representation. |
| **Input Encoding** | String | No | How to decode the input. Defaults to UTF-8. |
| **Output Encoding** | String | No | How to encode the result. Defaults to Base64. |
Supported options are UTF-8, Base64, Base64 URL, Hex, ASCII, UTF-16LE, UCS-2,
Latin-1, and Binary.
## Output
| Output | Type | Description |
| ------------------ | ------ | ---------------------------- |
| **Converted Text** | String | Text in the target encoding. |
For example, UTF-8 text `hello` converted to Base64 returns `aGVsbG8=`.
Set **Input Encoding** to the format the input already uses. Choosing Base64
for ordinary text attempts to decode that text as Base64 rather than encode
it.
# Format Number
Source: https://learn.workflow.dog/reference/actions/core/format-number
Render a number as localized decimal, currency, percentage, or compact text.
**Format Number** uses the `en-US` locale and returns display text rather than
a numeric value.
## Inputs
| Input | Type | Required | Description |
| ------------------ | ------ | --------- | ----------------------------------------------------------- |
| **Number** | Number | Yes | Value to format. |
| **Format Type** | String | Yes | Decimal, Currency, Percentage, or Compact. |
| **Decimal Places** | Number | Sometimes | `0`–`20`; used by decimal, percentage, and compact formats. |
| **Currency** | String | Sometimes | ISO currency code; appears for Currency. Defaults to USD. |
## Output
| Output | Type | Description |
| ------------- | ------ | ----------------------------- |
| **Formatted** | String | The localized display string. |
`1234.5` with two decimal places becomes `1,234.50`.
`1234.5` in USD becomes `$1,234.50`. Currency controls its conventional
number of decimal places.
The input is a ratio: `0.125` with one decimal place becomes `12.5%`.
`1200` with one decimal place becomes `1.2K`.
# Get Project Variable
Source: https://learn.workflow.dog/reference/actions/core/get-project-var
Load a persistent value shared across the current project.
## Inputs
| Input | Type | Required | Description |
| ----------------- | ------ | -------- | ----------------------------------------- |
| **Key** | String | Yes | Name of the project variable to retrieve. |
| **Default Value** | Any | No | Returned when the key does not exist. |
## Output
| Output | Type | Description |
| --------- | ---- | ----------------------------------------- |
| **Value** | Any | The stored value, the default, or `null`. |
When the key is missing and **Default Value** is unconnected, the result is
`null`. Reading a value does not change it.
Project variable keys are shared by all workflows in the project. Use a naming
convention such as `billing.last_sync` to avoid accidental overlap.
# Is True/False?
Source: https://learn.workflow.dog/reference/actions/core/is-boolean
Check whether a value is a Boolean.
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------ |
| **Result** | Boolean | `true` only when the value is `true` or `false`. |
Truthy numbers and strings are not Boolean values.
# Is Null?
Source: https://learn.workflow.dog/reference/actions/core/is-null
Check whether a value is null or missing.
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
| Output | Type | Description |
| ---------- | ------- | ------------------------------------- |
| **Result** | Boolean | `true` for `null` or a missing value. |
Empty text, `0`, `false`, empty lists, and empty objects return `false`.
# Is Number?
Source: https://learn.workflow.dog/reference/actions/core/is-number
Check whether a value has the Number type.
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
| Output | Type | Description |
| ---------- | ------- | ---------------------------------- |
| **Result** | Boolean | `true` when the value is a number. |
Numeric text such as `"42"` returns `false`. Use **Convert to Number** first
when coercion is desired.
# Parse JSON
Source: https://learn.workflow.dog/reference/actions/core/json-parse
Convert JSON text into a workflow value.
## Input
| Input | Type | Required | Description |
| -------- | ------ | -------- | ---------------- |
| **JSON** | String | Yes | Valid JSON text. |
## Output
| Output | Type | Description |
| ---------- | ---- | --------------------------------------------------- |
| **Parsed** | Any | The object, list, string, number, Boolean, or null. |
```json theme={null}
{ "customer": { "id": 42 }, "active": true }
```
The example produces an object whose `customer.id` is the number `42`.
JSON does not allow comments, trailing commas, or single-quoted strings. A
syntax error fails the action.
# Convert to JSON
Source: https://learn.workflow.dog/reference/actions/core/json-stringify
Serialize a workflow value as JSON text.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------- | -------- | ------------------------------------------------- |
| **Value** | Any | Yes | The value to serialize. |
| **Pretty** | Boolean | No | Indent nested JSON by two spaces. Defaults to on. |
## Output
| Output | Type | Description |
| -------- | ------ | ------------------------- |
| **JSON** | String | The serialized JSON text. |
Turn **Pretty** off for compact payloads sent to APIs. Keep it on when humans
will read the result.
JSON cannot represent every runtime value. Unsupported object properties may
be omitted, and circular structures cause serialization to fail.
# Loop Workflow
Source: https://learn.workflow.dog/reference/actions/core/loop-workflow
Run a callable workflow once for each item in a list.
**Loop Workflow** sends every payload to the selected workflow and collects the
returned values in the same order.
## Inputs
| Input | Type | Required | Description |
| --------------------- | -------- | -------- | ------------------------------------------------ |
| **Selected Workflow** | Workflow | Yes | Callable workflow to run for each item. |
| **Payloads** | List | No | Items to process, up to 1,000. Defaults to `[]`. |
## Output
| Output | Type | Description |
| ----------- | ---- | ------------------------------------------------ |
| **Results** | List | One child result per payload, in matching order. |
Each item becomes **Data In** in the child workflow. A child run without
**Return Data** contributes `null` to the result list.
Iterations run sequentially, not in parallel. This preserves order but means
total runtime grows with the number and duration of child runs.
If any child run fails, this action fails and does not return partial results.
Recursive workflow calls are also rate-limited to prevent infinite loops.
# Null
Source: https://learn.workflow.dog/reference/actions/core/null
Produce an explicit null value.
**Null** has no inputs.
| Output | Type | Description |
| -------- | ---- | ----------------- |
| **Null** | Null | The value `null`. |
Use it when an action must receive an explicit “no value” rather than an
unconnected input.
# Number
Source: https://learn.workflow.dog/reference/actions/core/number
Provide a fixed numeric value.
Enter a number directly on the compact node.
| Input | Type | Required | Description |
| ---------- | ------ | -------- | -------------------------- |
| **Number** | Number | Yes | The numeric value to emit. |
| Output | Type | Description |
| ------ | ------ | ------------------- |
| | Number | The entered number. |
If the input cannot be parsed as a number, the server produces `null`.
# Return Data
Source: https://learn.workflow.dog/reference/actions/core/return-data
Return a value to the workflow that called this sub-workflow.
**Return Data** is available for workflows using the **Sub-Workflow** trigger.
It sends a response back to **Run Workflow**, **Loop Workflow**, or another
calling action.
## Input
| Input | Type | Required | Description |
| -------- | ---- | -------- | --------------------------------- |
| **Data** | Any | Yes | The value returned to the caller. |
The calling action receives this value as its result or corresponding loop
item.
If a callable workflow finishes without returning data, callers use `null` as
its result.
# Run Workflow
Source: https://learn.workflow.dog/reference/actions/core/run-workflow
Run a callable workflow and wait for its returned data.
**Run Workflow** starts another workflow, waits for it to finish, and exposes
the value it returns.
## Quick start
Give it the **Sub-Workflow** trigger. Use **Data from Trigger** to read
**Data In**, and **Return Data** to send a result back.
Choose it in **Selected Workflow**, or connect a **Callable Workflow**
value.
Connect an optional **Payload** and use **Result** after the child run
completes.
## Inputs
| Input | Type | Required | Description |
| --------------------- | -------- | -------- | ----------------------------------- |
| **Selected Workflow** | Workflow | Yes | Callable workflow to run. |
| **Payload** | Any | No | Passed to the child as **Data In**. |
## Output
| Output | Type | Description |
| ---------- | ---- | --------------------------------------------------- |
| **Result** | Any | Returned child data, or `null` if none is returned. |
If the child run fails, this action fails with the child run's failure
message. Recursive workflow calls are rate-limited to prevent infinite loops.
# Schedule Workflow
Source: https://learn.workflow.dog/reference/actions/core/schedule-workflow
Queue a callable workflow to run at a future date and time.
**Schedule Workflow** creates a future child run and completes without waiting
for that run to execute.
## Inputs
| Input | Type | Required | Description |
| --------------------- | ----------- | -------- | ----------------------------------- |
| **Selected Workflow** | Workflow | Yes | Callable workflow to schedule. |
| **Date & Time** | Date & Time | Yes | Exact instant for the child run. |
| **Payload** | Any | No | Passed to the child as **Data In**. |
The scheduled child workflow can read the payload through **Data from
Trigger**. This action has no result output because it does not wait for the
future run.
**Date & Time** must be at least 10 seconds in the future when this action
executes. A date too close to the present fails with `Date must be in the
future`.
Scheduling confirms that the run was queued, not that it eventually succeeded.
Use a project variable, email, or another durable side effect in the child
workflow when completion must be observable.
# Send Email
Source: https://learn.workflow.dog/reference/actions/core/send-email
Send a Markdown email to members of the current project.
**Send Email** delivers a notification from the current WorkflowDog project.
For safety, it cannot send to addresses that are not project members.
## Inputs
| Input | Type | Required | Description |
| ------------------------ | ----------------- | --------- | ------------------------------------------ |
| **Send to all members?** | Boolean | No | Send to every current project member. |
| **Recipients** | Repeatable string | Sometimes | Required when sending to selected members. |
| **Subject** | String | Yes | Email subject line. |
| **Body** | String | Yes | Message body with Markdown support. |
When **Send to all members?** is on, the **Recipients** input disappears and
membership is resolved when the action runs.
## Example
```markdown theme={null}
## Import complete
Processed **{{count}}** records for {{customer}}.
```
Build dynamic content with a **Text** action, then connect the rendered result
to **Body**.
Every explicitly supplied address must exactly match a current member of the
project. If any recipient is not a member, the entire action fails and sends
no email.
Duplicate recipient addresses are removed. The sender name uses the project
name and a project-specific WorkflowDog notification address.
# Set Project Variable
Source: https://learn.workflow.dog/reference/actions/core/set-project-var
Store a persistent value shared across the current project.
## Inputs
| Input | Type | Required | Description |
| --------- | ------ | -------- | ------------------------------------ |
| **Key** | String | Yes | Name under which to store the value. |
| **Value** | Any | Yes | Value to save. |
The action has no output. If the key already exists, its previous value is
replaced.
Project variables preserve supported WorkflowDog data types rather than
reducing everything to plain text. Use **Get Project Variable** with the same
key to load the value later.
Project variables are shared by all workflows in the project. Reusing a key
intentionally overwrites its value for every workflow.
# Text
Source: https://learn.workflow.dog/reference/actions/core/text
Provide fixed text or render a Handlebars template.
**Text** emits exactly what you type unless the text contains template
expressions such as `{{name}}`. Each top-level template variable becomes a
connectable input on the node.
## Inputs
| Input | Type | Required | Description |
| ------------------ | ------- | --------- | --------------------------------------------- |
| **Text** | String | Yes | Fixed text or a Handlebars template. |
| **Sensitive** | Boolean | No | Mask the text on the canvas. Defaults to off. |
| Template variables | Any | Sometimes | Created from expressions in the text. |
## Output
| Output | Type | Description |
| ------ | ------ | ------------------ |
| | String | The rendered text. |
## Example
```handlebars theme={null}
Hello
{{customer.name}}!
{{#if urgent}}This request is urgent.{{/if}}
```
The node exposes **customer** and **urgent** inputs. Connect an object to
**customer** and a value to **urgent**.
Template values are inserted without HTML escaping. **Sensitive** only masks
the canvas display; the value remains visible in the configuration panel and
is still passed through the workflow.
Renaming or removing a template variable removes its corresponding input.
Check downstream connections after editing template expressions.
# Throw Error
Source: https://learn.workflow.dog/reference/actions/core/throw-error
Fail the current workflow run with a custom message.
## Input
| Input | Type | Required | Description |
| ----------- | ------ | -------- | ----------------------------------- |
| **Message** | String | Yes | The error shown for the failed run. |
When this action executes, it throws immediately. Actions that depend on its
completion do not run.
Use it after validation or on a failure branch. For example, when a required
customer ID is missing, connect that branch to **Throw Error** and set
**Message** to `Customer ID is required`.
# Convert to True/False
Source: https://learn.workflow.dog/reference/actions/core/to-boolean
Convert an arbitrary value into a Boolean.
| Input | Type | Required | Description |
| --------- | ---- | -------- | --------------------- |
| **Value** | Any | Yes | The value to convert. |
| Output | Type | Description |
| ----------- | ------- | ------------------------------- |
| **Boolean** | Boolean | The converted true/false value. |
The following become `false`:
* `null`, `false`, `0`, empty text, and missing values
* The text `"false"` in any capitalization
All other values become `true`, including empty lists, empty objects, and text
containing spaces.
# Convert to Number
Source: https://learn.workflow.dog/reference/actions/core/to-number
Coerce a value into a number.
| Input | Type | Required | Description |
| --------- | ---- | -------- | --------------------- |
| **Value** | Any | Yes | The value to convert. |
| Output | Type | Description |
| ---------- | ------ | ---------------------------- |
| **Number** | Number | The converted numeric value. |
Numeric text such as `"42.5"` becomes `42.5`. `true` becomes `1`, `false`
becomes `0`, and empty text becomes `0`.
The action fails when the input cannot be coerced to a valid number. Use **Is
Number?** only to test existing types; it does not predict every value that
this action can convert.
# Data from Trigger
Source: https://learn.workflow.dog/reference/actions/core/trigger-data
Access the data that started the current workflow run.
**Data from Trigger** changes its name and outputs to match the workflow's
selected trigger.
Examples include:
* **Data In** for a Sub-Workflow trigger
* Sender, subject, body, and attachments for a Mail Hook
* **Timestamp** for a Schedule trigger
Add the node after selecting a trigger, then connect only the event fields the
workflow needs.
Changing the workflow trigger changes this node's available outputs. Review
connections after switching triggers.
# Callable Workflow
Source: https://learn.workflow.dog/reference/actions/core/workflow
Select a callable workflow and expose it as a value.
**Callable Workflow** lets the workflow choose which sub-workflow another
action should run. Connect its output to **Run Workflow**, **Loop Workflow**,
or another action that accepts a workflow value.
## Input
| Input | Type | Required | Description |
| ------------ | -------- | -------- | ------------------------------------ |
| **Workflow** | Workflow | Yes | A callable workflow in this project. |
## Output
| Output | Type | Description |
| ------------ | -------- | ------------------------------------------ |
| **Workflow** | Workflow | The selected workflow, including its name. |
The server verifies that the workflow exists in the current project.
# Convert to YAML
Source: https://learn.workflow.dog/reference/actions/core/yaml-stringify
Serialize a workflow value as YAML text.
## Inputs
| Input | Type | Required | Description |
| ------------------- | ------- | -------- | -------------------------------------------------------------------------- |
| **Value** | Any | Yes | The value to serialize. |
| **Use references?** | Boolean | No | Represent repeated objects with YAML anchors and aliases. Defaults to off. |
## Output
| Output | Type | Description |
| -------- | ------ | --------------------------------- |
| **YAML** | String | YAML using two-space indentation. |
Lines wrap at approximately 80 characters. Enable references when a repeated
object should be emitted once and reused with aliases; leave it off for
simpler standalone YAML.
# Current Date & Time
Source: https://learn.workflow.dog/reference/actions/datetime/current
Capture the date and time when the action runs.
**Current Date & Time** has no inputs. It reads the clock at execution time,
not when the workflow is saved or opened.
## Output
| Output | Type | Description |
| -------- | ----------- | ------------------------------------ |
| **Date** | Date & Time | The instant at which the action ran. |
Use **Format Date/Time** afterward when another action needs text in a
particular timezone or display style.
# Date & Time
Source: https://learn.workflow.dog/reference/actions/datetime/datetime
Provide a fixed date and time to a workflow.
**Date & Time** is a compact value node. Choose a date and local time in the
editor; the value is stored as an exact ISO timestamp.
## Input
| Input | Type | Required | Description |
| --------------- | ----------- | -------- | ------------------------------ |
| **Date & Time** | Date & Time | Yes | The fixed date and time value. |
## Output
| Output | Type | Description |
| ------ | ----------- | --------------------------- |
| | Date & Time | The selected date and time. |
The editor interprets the entered clock time in the browser's local timezone,
then stores the corresponding instant. If the workflow must construct a time
relative to execution, use **Relative Date** instead.
# Format Date/Time
Source: https://learn.workflow.dog/reference/actions/datetime/format-date
Convert a date and time into display-ready text.
**Format Date/Time** renders one instant in a chosen timezone. Use preset date
and time styles for localized English output, or enable a custom formatting
expression for exact control.
## Inputs
| Input | Type | Required | Description |
| ------------------------------- | ----------- | -------- | ------------------------------------------- |
| **Date & Time** | Date & Time | Yes | The instant to format. |
| **Use a formatting expression** | Boolean | No | Switch from presets to a custom expression. |
| **Timezone** | String | Yes | IANA timezone used to display the instant. |
The timezone defaults to the browser's current timezone when the node is
created.
**Date Style** and **Time Style** each support `short`, `medium`, `long`,
`full`, or `none`. Defaults are `medium` for the date and `short` for the
time. Choose `none` to omit either part.
**Expression** uses Day.js formatting tokens and defaults to
`DD/MM/YYYY h:mm`.
For example, `YYYY-MM-DD HH:mm` can produce `2026-07-24 15:30`.
## Output
| Output | Type | Description |
| ------------- | ------ | ------------------------------------ |
| **Formatted** | String | The formatted date and time as text. |
Toggling expression mode replaces the preset inputs. Check the format after
switching an existing node.
# Date from Text
Source: https://learn.workflow.dog/reference/actions/datetime/natural-language-date
Parse a date from a natural-language expression.
**Date from Text** understands phrases such as `in 2 days`, `next Friday`, or
`tomorrow at 9am`.
## Inputs
| Input | Type | Required | Description |
| ----------------- | ----------- | -------- | ------------------------------------------------ |
| **Expression** | String | Yes | Natural-language date or time to parse. |
| **Starting Date** | Date & Time | No | Reference instant. Defaults to the current time. |
| **Timezone** | String | Yes | Timezone used to interpret the expression. |
## Output
| Output | Type | Description |
| -------- | ----------- | ------------------- |
| **Date** | Date & Time | The parsed instant. |
For predictable results, make the phrase explicit:
```text theme={null}
next Friday at 9:00 AM
```
Set **Starting Date** in tests so relative phrases do not change from one run
to the next.
Natural-language parsing is experimental and can interpret ambiguous phrases
differently than intended. The action fails with `Couldn't parse date` when it
cannot recognize the expression.
# Relative Date
Source: https://learn.workflow.dog/reference/actions/datetime/relative-date
Add a duration to a starting date and time.
## Inputs
| Input | Type | Required | Description |
| ----------------- | ----------- | -------- | ----------------------------------------------------------- |
| **Amount** | Number | Yes | Amount to add. Use a negative value to subtract. |
| **Unit** | String | Yes | Minutes, hours, days, weeks, or months. Defaults to hours. |
| **Starting Date** | Date & Time | No | Reference instant. Intended to default to the current time. |
## Output
| Output | Type | Description |
| -------- | ----------- | ----------------------------- |
| **Date** | Date & Time | The calculated date and time. |
For example, an amount of `-2` and a unit of `days` returns two calendar days
before the starting date.
Days, weeks, and months use calendar arithmetic. Month lengths vary, and
daylight-saving changes can make a calendar day differ from exactly 24 elapsed
hours.
The current server initializes the blank **Starting Date** default when the
Date & Time package loads, rather than for each action run. Connect **Current
Date & Time** explicitly when the calculation must start at execution time.
# Create Text File
Source: https://learn.workflow.dog/reference/actions/files/create-text-file
Turn string content into a named file.
**Create Text File** packages a string as a file that can be uploaded, emailed,
stored, or returned from a workflow.
## Inputs
| Input | Type | Required | Description |
| ------------- | ------ | -------- | ------------------------------------------------------------- |
| **Content** | String | Yes | The complete text written to the file. |
| **File Name** | String | Yes | The output name, including an extension such as `report.csv`. |
## Output
| Output | Type | Description |
| -------- | ---- | ------------------------------------ |
| **File** | File | A file containing the supplied text. |
The MIME type is inferred from the filename when its extension is recognized.
Include the correct extension in **File Name**. For example, use `.json` for
JSON content and `.html` for an HTML document.
# Convert Data URL to File
Source: https://learn.workflow.dog/reference/actions/files/data-url-to-file
Decode a base64 data URL into a file.
**Convert Data URL to File** decodes an embedded base64 value and returns a
file with the matching MIME type.
## Input and output
| Direction | Field | Type | Description |
| --------- | ------------ | ------ | ------------------------------------------------- |
| Input | **Data URL** | String | A base64 URL such as `data:image/png;base64,...`. |
| Output | **File** | File | The decoded file. |
The output is named `converted.EXTENSION`, where the extension is inferred
from the MIME type.
The input must use the exact `data:MIME_TYPE;base64,DATA` form. Non-base64
data URLs and MIME types without a known file extension are rejected.
# Download File from URL
Source: https://learn.workflow.dog/reference/actions/files/download-from-url
Fetch a public URL and return its response as a file.
**Download File from URL** retrieves a public resource and turns the response
bytes into a WorkflowDog file.
## Inputs
| Input | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------ |
| **URL** | String | Yes | The complete public URL to download. |
| **Filename** | String | No | A custom output filename. |
## Output
| Output | Type | Description |
| -------- | ---- | ----------------------- |
| **File** | File | The downloaded content. |
When **Filename** is empty, the action uses the last part of the URL path. If
that name has no extension, `.bin` is added. The response's `Content-Type`
header supplies the MIME type when available; otherwise it is inferred from
the filename.
Internal, local, and private network addresses are blocked. The action also
fails when the remote server returns a non-success HTTP status.
# Convert File to Data URL
Source: https://learn.workflow.dog/reference/actions/files/file-to-data-url
Encode a file as a base64 data URL.
**Convert File to Data URL** embeds a file's MIME type and base64-encoded bytes
in a single string.
## Input and output
| Direction | Field | Type | Description |
| --------- | ------------ | ------ | -------------------------------------------------- |
| Input | **File** | File | The file to encode. |
| Output | **Data URL** | String | A string in the form `data:MIME_TYPE;base64,DATA`. |
Data URLs are useful when an API or HTML document expects embedded content
instead of a separate file.
Base64 increases the size of the data. Prefer a normal file upload when the
receiving service supports one.
# Rename File
Source: https://learn.workflow.dog/reference/actions/files/rename
Create a copy of a file with a different name.
**Rename File** preserves a file's contents and MIME type while changing its
name.
| Direction | Field | Type | Description |
| --------- | ---------------- | ------ | -------------------------------------- |
| Input | **File** | File | The original file. |
| Input | **Name** | String | The new name, including any extension. |
| Output | **Renamed File** | File | A copy with the new name. |
Renaming does not convert the file. Changing `.png` to `.jpg`, for example,
does not change the underlying image format or MIME type.
# Crawl Website
Source: https://learn.workflow.dog/reference/actions/firecrawl/crawl
Crawl multiple pages from a site and return content, links, and screenshots.
**Crawl Website** starts an asynchronous Firecrawl crawl at one URL, waits for
it to finish, and returns every completed page as a list. Use it when you need
site-wide content rather than a single page.
The workflow remains on this action while Firecrawl is scraping. The node
checks the crawl every two seconds and fails if Firecrawl reports a failed
crawl.
## Crawl inputs
| Input | Type | Required | Description |
| --------------------------- | ----------------- | -------- | ------------------------------------------------------------------------------ |
| **Third-party account** | Firecrawl account | Yes | The Firecrawl API key used for the crawl. |
| **URL** | String | Yes | The starting URL. |
| **Limit** | Integer | Yes | Maximum pages to crawl, from `1` to `1000`. Defaults to `100`. |
| **Max Depth** | Integer | Yes | Maximum link depth from the starting URL, from `1` to `100`. Defaults to `10`. |
| **Ignore Query Parameters** | Boolean | No | Treats URL variants that differ only by query parameters as the same page. |
| **Allow Backward Links** | Boolean | No | Allows the crawl to move to parent paths outside the starting URL's path. |
## Per-page scrape inputs
These settings are applied to every page visited:
| Input | Type | Default | Description |
| ------------------------ | -------------------------------- | ------- | --------------------------------------------------------------- |
| **Format** | `markdown`, `html`, or `rawHtml` | `html` | Content representation for each page. |
| **Include Links** | Boolean | Off | Includes links found on each page. |
| **Include Screenshot** | Boolean | Off | Includes a screenshot for each page. |
| **Full Page Screenshot** | Boolean | Off | Captures full-page screenshots when screenshots are enabled. |
| **Only Main Content** | Boolean | On | Excludes headers, navigation, footers, and similar page chrome. |
| **Mobile** | Boolean | Off | Emulates a mobile device. |
| **Headers** | List of name/value pairs | Empty | Headers sent while scraping. |
| **Wait For** | Number | `0` | Milliseconds to wait before extracting each page. |
| **Remove Base64 Images** | Boolean | On | Removes embedded base64 image data while retaining alt text. |
## Outputs
| Output | Type | Description |
| --------- | --------------- | -------------------------------------------------------------------------------------------------------- |
| **Total** | Number | Number of pages returned by the completed crawl. |
| **Pages** | List of objects | Crawled pages, each containing **URL**, **Content**, and any enabled **Links** or **Screenshot** values. |
Expanding **Pages** gives each page:
| Property | Type | Description |
| -------------- | --------------- | ----------------------------------------------- |
| **URL** | String | Firecrawl's source URL for the page. |
| **Content** | String | Content in the selected format. |
| **Links** | List of strings | Present when **Include Links** is enabled. |
| **Screenshot** | File | Present when **Include Screenshot** is enabled. |
## Scope the crawl deliberately
Start with a modest **Limit** and **Max Depth**, inspect the returned URLs, and
increase them only when needed. Query-heavy sites can expose many near-duplicate
URLs; **Ignore Query Parameters** helps keep those from consuming the page
limit.
Screenshots multiply the work and data produced by a crawl. Enable them only
when downstream steps actually need an image for every page.
## Troubleshooting
Enable **Ignore Query Parameters** and lower **Max Depth**. Tracking,
filtering, and pagination parameters often create many URL variants.
Enable **Allow Backward Links**. Leave it off when the crawl should stay
within a subsection of a site.
Reduce **Limit**, **Max Depth**, and **Wait For**. Full-page screenshots on
every page also add substantial work.
# Scrape URL
Source: https://learn.workflow.dog/reference/actions/firecrawl/scrape
Extract page content, links, and an optional screenshot with Firecrawl.
**Scrape URL** loads one web page through Firecrawl and returns its content as
HTML, raw HTML, or Markdown. It can also collect page links and capture a
screenshot in the same request.
## Inputs
| Input | Type | Required | Description |
| ------------------------ | -------------------------------- | -------- | ----------------------------------------------------------------------------------------------- |
| **Third-party account** | Firecrawl account | Yes | The Firecrawl API key used for the request. |
| **URL** | String | Yes | The complete page URL to scrape. |
| **Format** | `markdown`, `html`, or `rawHtml` | Yes | The content representation. Defaults to `html`. |
| **Include Links** | Boolean | No | Adds the page's discovered links to the output. Defaults to off. |
| **Include Screenshot** | Boolean | No | Adds a screenshot file to the output. Defaults to off. |
| **Full Page Screenshot** | Boolean | No | When screenshots are enabled, captures the full page instead of the viewport. |
| **Only Main Content** | Boolean | No | Excludes navigation, headers, footers, and similar surrounding content. Defaults to on. |
| **Mobile** | Boolean | No | Emulates a mobile device while scraping. Defaults to off. |
| **Headers** | List of name/value pairs | No | Request headers, such as a cookie or user-agent. |
| **Wait For** | Number | No | Time to wait before scraping, in milliseconds. Defaults to `0`. |
| **Remove Base64 Images** | Boolean | No | Replaces embedded base64 image data with placeholders while retaining alt text. Defaults to on. |
Headers can contain credentials. Only send them to URLs you trust, and avoid
exposing private session cookies in workflow outputs or logs.
## Outputs
| Output | Type | Available when | Description |
| -------------- | --------------- | ---------------------------- | ------------------------------------ |
| **Content** | String | Always | Page content in the selected format. |
| **Links** | List of strings | **Include Links** is on | Links Firecrawl found on the page. |
| **Screenshot** | File | **Include Screenshot** is on | The downloaded page screenshot. |
Changing either include toggle changes the node's output handles. Check
downstream connections after turning one off.
## Choosing a format
* `markdown` produces compact content suited to summaries, search indexing,
and language-model prompts.
* `html` returns Firecrawl's cleaned HTML representation.
* `rawHtml` preserves the page's original HTML more closely.
Use **Only Main Content** with Markdown or HTML when page chrome is noise. Turn
it off when headers, navigation, or footer content is part of what you need.
## Troubleshooting
Turn off **Only Main Content** if the text is outside the page's detected
main region. Increase **Wait For** when the content appears after load.
Keep **Remove Base64 Images** on, use `markdown`, and enable **Only Main
Content**. Embedded images and raw HTML can make results much larger.
Confirm **Include Screenshot** is enabled. Firecrawl must return a
screenshot URL for the node to download a file.
# Search Web
Source: https://learn.workflow.dog/reference/actions/firecrawl/search
Search the web with Firecrawl and return titles, descriptions, and URLs.
**Search Web** sends a search query through Firecrawl and returns structured
search results. It is useful for discovering pages before scraping or crawling
them.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ----------------- | -------- | ------------------------------------------------------------------------------------ |
| **Third-party account** | Firecrawl account | Yes | The Firecrawl API key used for search. |
| **Query** | String | Yes | The search terms. An empty query is rejected. |
| **Limit** | Integer | Yes | Maximum results, from `1` to `100`. Defaults to `5`. |
| **Location** | String | No | A geographic location used to localize results. |
| **Time Filter** | Enum | No | Restricts results to the past hour, day, week, month, or year. Defaults to any time. |
Available time filters are:
* **Any time**
* **Past hour**
* **Past 24 hours**
* **Past week**
* **Past month**
* **Past year**
If you expand **Results** into a fixed number of output entries, that entry
count becomes the requested result limit. Otherwise the action uses **Limit**.
## Outputs
| Output | Type | Description |
| ----------- | --------------- | ------------------------------------------------------------ |
| **Total** | Number | Number of results Firecrawl returned. |
| **Results** | List of objects | Search results with **Title**, **Description**, and **URL**. |
Search results identify candidate pages; they do not contain the full page
body. Connect a selected **URL** to **Scrape URL** when you need its content.
## Example: research recently updated pages
Search for a focused query, set **Time Filter** to **Past month**, and expand
the first few **Results**. Use their descriptions for an initial relevance
check, then scrape only the URLs you decide to process.
## Troubleshooting
The limit is a maximum, not a guarantee. The time filter, location, and
available matches can reduce the result count.
Check whether **Results** has been expanded into individual entries. Its
configured entry count takes precedence over **Limit**.
# Autocomplete Places
Source: https://learn.workflow.dog/reference/actions/geo/autocomplete-places
Find likely places and search suggestions from partial text.
**Autocomplete Places** uses fuzzy matching to turn partial names, addresses,
misspellings, or plus codes into Google place predictions.
## Inputs
| Input | Type | Required | Description |
| ------------------------------ | --------------- | -------- | ------------------------------------------------------------------------------------ |
| **Input** | String | Yes | The search text. |
| **Latitude** | Number | No | Center latitude for location-biased results. |
| **Longitude** | Number | No | Center longitude for location-biased results. |
| **Radius Meters** | Number | No | Bias radius from `0` to `50,000`. Defaults to `5,000` when coordinates are supplied. |
| **Include Query Predictions?** | Boolean | No | Also return alternative search phrases. |
| **Region Codes** | List of strings | No | Up to 15 two-character country codes, such as `US` and `CA`. |
Location bias is applied only when both **Latitude** and **Longitude** are
present. A radius without both coordinates has no effect.
## Outputs
| Output | Type | Description |
| --------------------- | --------------- | ------------------------------------------------------------------------------------------------ |
| **Top Place ID** | String | The Google Place ID from the first place prediction. |
| **Top Place Text** | String | The formatted text of the first place prediction. |
| **Place Predictions** | List of objects | All matches, including place ID, text, primary and secondary text, types, and optional distance. |
| **Query Predictions** | List of objects | Suggested search text when query predictions are enabled. |
When there are no place matches, the top outputs are empty and **Place
Predictions** is an empty list.
# Validate Address
Source: https://learn.workflow.dog/reference/actions/geo/refine-address
Standardize an address and return location and deliverability details.
**Validate Address** sends a street address to Google's Address Validation API.
It returns standardized address parts, coordinates, a Place ID, and
deliverability signals.
## Inputs
| Input | Type | Required | Description |
| ---------------------- | ------- | -------- | --------------------------------------------------------------------------- |
| **Address** | String | Yes | The complete address to validate. |
| **Get Full Zip Code?** | Boolean | No | Return a ZIP+4 value when Google or USPS provides one. |
| **Enable USPS CASS?** | Boolean | No | Request USPS CASS standardization and delivery-point data for US addresses. |
## Outputs
| Output | Type | Description |
| --------------------------------------- | ------- | -------------------------------------------------------------------- |
| **Formatted Address** | String | Google's standardized complete address. |
| **Address Line 1** / **Address Line 2** | String | Standardized street lines. |
| **City** / **State** / **Zip Code** | String | Parsed locality and postal fields. |
| **Latitude** / **Longitude** | Number | Geocoded coordinates. |
| **Place ID** | String | Google's stable identifier for the location. |
| **Is Residential** / **Is Business** | Boolean | Address metadata when available. |
| **Is Deliverable** | Boolean | True when the address is complete and has no unconfirmed components. |
Some outputs can be empty when the service cannot confirm that detail. Treat
**Is Deliverable** as the clearest validation signal rather than assuming a
formatted address is deliverable.
## Example: clean a shipping address
Connect the customer's raw address to **Address**, enable USPS CASS for US
shipments, and store **Formatted Address** for display. Continue fulfillment
only when **Is Deliverable** is true; otherwise route the order for review.
# Add Label
Source: https://learn.workflow.dog/reference/actions/gmail/add-label
Apply a Gmail label to one message.
The **Add Label** action applies an existing Gmail label to a message. Use it
to categorize processed mail, route inbox work, or mark a workflow stage.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to update. |
| **Label** | String | Yes | Existing Gmail label name or label ID. |
Label names are matched after trimming whitespace and ignoring capitalization.
Supplying an exact Gmail label ID also works.
This action has no output. A successful run means Gmail accepted the label
update.
## Example
Use **Search Messages** to find the relevant mail, repeat over its **Message
IDs**, and apply the `Processed` label to each message with **Add Label**.
## Troubleshooting
The action does not create labels. Create the label in Gmail first, then use
its visible name or exact ID.
# Delete Draft
Source: https://learn.workflow.dog/reference/actions/gmail/delete-draft
Permanently delete a Gmail draft.
The **Delete Draft** action deletes an unsent draft from the connected Gmail
account.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ---------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account that owns the draft. |
| **Message ID** | String | Yes | Identifier of the draft to delete. |
The identifier returned by **Draft Email** or **Draft Reply** can be connected
directly.
Deleting a draft is permanent and this action has no output. Do not pass the
ID of a draft that still needs human review.
## Troubleshooting
Confirm the identifier belongs to an existing draft in the connected
account. A draft that was already sent or deleted no longer resolves.
# Draft Email
Source: https://learn.workflow.dog/reference/actions/gmail/draft-email
Create an unsent Gmail draft with optional recipients and attachments.
The **Draft Email** action saves a new message in Gmail without sending it. Use
it for human review, approval workflows, or messages that should be completed
manually in Gmail.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | -------------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account that owns the draft. |
| **Recipients** | List of email strings | No | `To` addresses. |
| **CC** | List of email strings | No | Carbon-copy addresses. |
| **Subject** | String | No | Draft subject. Defaults to an empty subject. |
| **Body** | String | No | Draft content. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files to include in the draft. |
Because this action creates a draft, recipients and message content can remain
empty and be completed later in Gmail.
## Outputs
| Output | Type | Description |
| -------------- | ------ | ------------------------------------------ |
| **Message ID** | String | Identifier returned for the created draft. |
Despite its label, this output is the identifier accepted by **Delete Draft**.
## Example: prepare a message for approval
Generate the customer update with an earlier action and connect the result to
the draft's **Body**. Once Gmail creates the draft, notify the reviewer that it
is ready.
## Troubleshooting
Use **Draft Email**, not **Send Email**. This action only saves the message
in the connected account's Drafts folder.
Choose **HTML** as the **Body Type** before providing markup.
# Draft Reply
Source: https://learn.workflow.dog/reference/actions/gmail/draft-reply
Create an unsent reply draft for a Gmail message.
The **Draft Reply** action prepares a reply in Gmail without sending it. It
keeps the original subject and conversation headers, so a reviewer can finish
or send the response from Gmail.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | -------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account that owns the draft. |
| **Message ID** | String | Yes | Gmail ID of the message being answered. |
| **Reply All** | Boolean | No | Include original `To` and `CC` recipients except this account. |
| **Body** | String | No | Draft reply content. Defaults to empty. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files to attach to the draft. |
## Outputs
| Output | Type | Description |
| -------------------- | ------ | --------------------------------------- |
| **Reply Message ID** | String | Identifier for the created reply draft. |
When **Reply All** is enabled, the finished draft includes original `To` and
`CC` recipients other than the connected account. Review the recipients before
sending.
## Example: human-review support reply
For a human-review workflow:
1. Use the incoming email to generate a suggested response.
2. Connect the original **Message ID** and suggested response to **Draft
Reply**.
3. Notify the support agent after Gmail creates the draft.
## Troubleshooting
Supply the Gmail Message ID for the message being answered. The action needs
that message's thread and RFC reply headers to construct the draft.
# Forward
Source: https://learn.workflow.dog/reference/actions/gmail/forward
Forward a Gmail message, including its original attachments.
The **Forward** action sends an existing Gmail message to one or more new
recipients. It preserves the original content and attachments, adds a forwarded
message block to the plain-text body, and keeps the message associated with the
original Gmail thread.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------------- | -------- | -------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account that sends the forward. |
| **Message ID** | String | Yes | Gmail ID of the message to forward. |
| **Recipients** | List of email strings | Yes | One or more addresses that receive it. |
## Outputs
| Output | Type | Description |
| ---------------------- | ------ | --------------------------------------------- |
| **Forward Message ID** | String | Gmail ID of the newly sent forwarded message. |
The subject receives `Fwd: ` unless it already starts with `Fwd:`. Original
attachments are downloaded and attached to the outgoing message.
Forwarding a message with large attachments requires downloading and
re-uploading those files during the workflow run.
## Troubleshooting
Forwarding requires the message's thread, raw content, From, Date, Subject,
and To data. Confirm the Message ID belongs to a complete message in the
connected mailbox.
Add each valid email address as a separate **Recipients** item.
# Get Message by ID
Source: https://learn.workflow.dog/reference/actions/gmail/get-message
Retrieve Gmail message content and optionally download its attachments.
The **Get Message by ID** action retrieves one Gmail message. It accepts either
Gmail's internal message ID or an RFC 822 `Message-ID`, making it useful with
Gmail triggers as well as IDs received from other mail systems.
## Quick start
Choose an account that can read the message.
Connect a Gmail **Message ID**, or supply an RFC 822 message ID such as a
value from an email's `Message-ID` header.
Enable **Download Attachments** only when later actions need the files.
Prefer **Plain Text** for text processing and **HTML** when preserving the
message's formatting.
## Inputs
| Input | Type | Required | Description |
| ------------------------ | -------------- | -------- | -------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account used to read the message. |
| **Message ID** | String | Yes | Gmail ID or RFC 822 message ID. |
| **Download Attachments** | Boolean | No | Whether to download attached files and expose **Attachments**. |
RFC 822 IDs are looked up across the mailbox, including Spam and Trash. Gmail
IDs are loaded directly.
## Outputs
| Output | Type | Description |
| ------------------ | ------------- | --------------------------------------------------- |
| **Message ID** | String | Canonical Gmail message ID. |
| **Thread ID** | String | Gmail conversation ID. |
| **Sender Name** | String | Parsed sender display name, when present. |
| **Sender Address** | String | Parsed sender email address, when present. |
| **Subject** | String | Message subject. |
| **Plain Text** | String | Plain-text MIME content, when present. |
| **HTML** | String | HTML MIME content, when present. |
| **Attachments** | List of files | Downloaded files when attachment downloading is on. |
**Attachments** is conditional. Turning off **Download Attachments** removes
that output from the node and avoids downloading file bodies.
## Troubleshooting
Use the Gmail ID returned by a Gmail action or trigger, or a complete RFC
822 `Message-ID`. The connected account must contain the message.
A message can contain only one of those MIME formats. Use the format the
sender supplied, or add fallback logic when processing varied mail.
# Has Label?
Source: https://learn.workflow.dog/reference/actions/gmail/has-label
Check whether a Gmail message has a specific label.
The **Has Label?** action resolves a Gmail label and checks whether it is
currently applied to one message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to inspect. |
| **Label** | String | Yes | Existing label name or exact label ID. |
Label names are resolved case-insensitively after trimming whitespace.
## Outputs
| Output | Type | Description |
| ------------- | ------- | --------------------------------------------- |
| **Has Label** | Boolean | Whether the resolved label is on the message. |
Use the boolean in an If action to avoid repeating work or to route labeled
messages differently.
## Troubleshooting
This action fails when the label does not exist. It returns `false` only
when the label exists but is not applied to the message.
# Is Important?
Source: https://learn.workflow.dog/reference/actions/gmail/is-important
Check whether Gmail marks a message as important.
The **Is Important?** action checks for Gmail's built-in `IMPORTANT` label on a
message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to inspect. |
## Outputs
| Output | Type | Description |
| ------------- | ------- | ---------------------------------------------- |
| **Important** | Boolean | Whether the message has the `IMPORTANT` label. |
Use this action before **Mark as Important** when the workflow should only
change messages that are not already important.
# Is Starred?
Source: https://learn.workflow.dog/reference/actions/gmail/is-starred
Check whether a Gmail message is starred.
The **Is Starred?** action checks for Gmail's built-in `STARRED` label on one
message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to inspect. |
## Outputs
| Output | Type | Description |
| ----------- | ------- | -------------------------------------------- |
| **Starred** | Boolean | Whether the message has the `STARRED` label. |
Route **Starred** into conditional logic when starred mail needs special
handling.
# Is Unread?
Source: https://learn.workflow.dog/reference/actions/gmail/is-unread
Check whether a Gmail message is unread.
The **Is Unread?** action checks whether one Gmail message carries the built-in
`UNREAD` label.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to inspect. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------- |
| **Unread** | Boolean | Whether the message has the `UNREAD` label. |
The result reflects the message's state when the action runs.
# Mark as Important
Source: https://learn.workflow.dog/reference/actions/gmail/mark-as-important
Mark one Gmail message as important.
The **Mark as Important** action adds Gmail's built-in `IMPORTANT` label to a
message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to update. |
This action has no output. Use **Is Important?** afterward only when a later
step needs an explicit boolean.
# Mark as Read
Source: https://learn.workflow.dog/reference/actions/gmail/mark-as-read
Mark one Gmail message as read.
The **Mark as Read** action removes Gmail's built-in `UNREAD` label from a
message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to update. |
The action returns no output. A successful run means Gmail accepted the state
change.
# Mark as Unread
Source: https://learn.workflow.dog/reference/actions/gmail/mark-as-unread
Mark one Gmail message as unread.
The **Mark as Unread** action adds Gmail's built-in `UNREAD` label to a message.
Use it to return processed mail to an inbox review queue or preserve a reminder
for a person.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to update. |
This action changes the message and returns no output.
# Remove Label
Source: https://learn.workflow.dog/reference/actions/gmail/remove-label
Remove an existing Gmail label from one message.
The **Remove Label** action removes one label from a Gmail message without
deleting the label itself.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to update. |
| **Label** | String | Yes | Existing Gmail label name or label ID. |
Label names are matched case-insensitively after surrounding whitespace is
removed. Exact label IDs are accepted as well.
This action has no output. It changes the message only; the label remains
available elsewhere in Gmail.
## Troubleshooting
Verify the label exists in the connected account. Labels belong to a
mailbox, so a name from another Google account may not resolve.
# Remove Reply Text
Source: https://learn.workflow.dog/reference/actions/gmail/remove-reply-text
Attempt to remove quoted reply history from plain-text email content.
The **Remove Reply Text** action cleans a common plain-text email reply format.
It removes carriage returns, looks for a line shaped like `On … wrote:`, and
strips the following quoted lines beginning with `>`.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ---------------------------------- |
| **Text** | String | Yes | Plain-text email content to clean. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | ----------------------------------------------------- |
| **Clean Text** | String | Trimmed text after matching reply history is removed. |
This is a best-effort text cleanup, not a complete email parser. Reply markers
vary across mail clients and languages, so unmatched history can remain.
## Example
Read a message with **Get Message by ID**, connect its **Plain Text** output to
**Remove Reply Text**, then pass **Clean Text** to the action that classifies
the message.
## Troubleshooting
The cleaner recognizes the common `On … wrote:` pattern followed by
newline-prefixed `>` quotes. Other formats, HTML replies, and custom
signatures are left unchanged.
# Send Reply
Source: https://learn.workflow.dog/reference/actions/gmail/reply
Reply to a specific Gmail message with optional attachments.
The **Send Reply** action sends a response to a specific Gmail message while
preserving the original conversation. It addresses the original `Reply-To`
header when present, otherwise the original sender.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | -------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account that sends the reply. |
| **Message ID** | String | Yes | Gmail ID of the message being answered. |
| **Reply All** | Boolean | No | Include original `To` and `CC` recipients except this account. |
| **Body** | String | Yes | Reply content. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files to attach to the reply. |
## Outputs
| Output | Type | Description |
| -------------------- | ------ | --------------------------- |
| **Reply Message ID** | String | Gmail ID of the sent reply. |
The action preserves the original subject and builds reply headers from the
selected message so Gmail keeps the response in its thread.
**Reply All** can notify every original `To` and `CC` recipient. Leave it off
when a private response is intended.
## Troubleshooting
The source message must have a subject, RFC message ID, reply or sender
address, and Gmail thread ID. Confirm the Message ID points to a complete
message in the connected mailbox.
Turn off **Reply All** to reply only to the original Reply-To or From
address.
# Send Reply to Thread
Source: https://learn.workflow.dog/reference/actions/gmail/reply-thread
Reply to the most recent inbox message in a Gmail thread.
The **Send Reply to Thread** action takes a Gmail thread ID, finds the most
recent message in that thread carrying the `INBOX` label, and replies to it.
Use it when your workflow tracks conversations rather than individual messages.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | -------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account that sends the reply. |
| **Thread ID** | String | Yes | Gmail conversation ID. |
| **Reply All** | Boolean | No | Include original `To` and `CC` recipients except this account. |
| **Body** | String | Yes | Reply content. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files to attach. |
## Outputs
| Output | Type | Description |
| -------------------- | ------ | --------------------------- |
| **Reply Message ID** | String | Gmail ID of the sent reply. |
The target is the newest inbox message in the thread, not necessarily the
newest message of any kind. A thread containing only sent messages cannot be
used by this action.
## Example: continue a stored conversation
Load the customer's stored thread ID and connect it to **Send Reply to Thread**.
After the reply is sent, store **Reply Message ID** if later actions need to
refer to that specific message.
## Troubleshooting
The thread must contain at least one message with Gmail's `INBOX` label. Use
**Send Reply** with a specific Message ID when you already know the message
to answer.
# Search Messages
Source: https://learn.workflow.dog/reference/actions/gmail/search-messages
Find Gmail message IDs using Gmail search syntax and date filters.
The **Search Messages** action searches a Gmail mailbox and returns matching
message IDs. Its query uses the same operators as Gmail's search bar.
## Inputs
| Input | Type | Required | Description |
| ------------------------ | -------------- | -------- | ----------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account whose mailbox is searched. |
| **Query** | String | Yes | Gmail search query. Whitespace-only text is ignored. |
| **Max Results** | Number | No | Maximum IDs to return, from `1` to `100`. Defaults to `10`. |
| **Include Spam & Trash** | Boolean | No | Whether Spam and Trash are included. Defaults to `false`. |
| **After Date** | Date | No | Only messages after this calendar date. |
| **Before Date** | Date | No | Only messages before this calendar date. |
The date inputs are appended to the Gmail query using `after:YYYY/M/D` and
`before:YYYY/M/D`. You can combine them with operators in **Query**:
```text theme={null}
from:billing@example.com has:attachment
```
## Outputs
| Output | Type | Description |
| --------------- | --------------- | ------------------------------------ |
| **Message IDs** | List of strings | Gmail IDs for the matching messages. |
This action returns identifiers only. Repeat over **Message IDs** and use **Get
Message by ID** when you need subjects, bodies, or attachments.
## Example: process recent invoices
Configure **Search Messages** with:
* **Query** — `subject:invoice has:attachment`
* **After Date** — The start of the current month.
Repeat over the returned **Message IDs** and pass each one to **Get Message by
ID** to load the invoice email's content and attachments.
## Troubleshooting
Test the same query in Gmail, check the date boundaries, and enable
**Include Spam & Trash** if those folders should be searched.
Increase **Max Results** up to `100`. The action returns a single result
page and does not expose pagination.
# Send Email
Source: https://learn.workflow.dog/reference/actions/gmail/send-email
Send a plain-text or HTML email from a connected Gmail account.
The **Send Email** action sends a new message from a connected Google account.
It supports multiple recipients, CC addresses, HTML bodies, and file
attachments.
## Quick start
Choose the Google account that should appear as the sender.
Add at least one **Recipients** item. Add **CC** items only when needed.
Set **Subject** and **Body**, then choose **Plain Text** or **HTML** for
**Body Type**.
Store **Message ID** for message actions or **Thread ID** for thread-level
replies.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | ---------------------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account that sends the message. |
| **Recipients** | List of email strings | Yes | One or more `To` addresses. |
| **CC** | List of email strings | No | Carbon-copy recipients. |
| **Subject** | String | Yes | Message subject. |
| **Body** | String | Yes | Plain-text or HTML message content. |
| **Body Type** | `Plain Text` or `HTML` | No | How the body is encoded. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files attached with their filename and content type. |
When **Body Type** is **HTML**, the body is sent as HTML. Escape or sanitize
untrusted values before inserting them into markup.
## Outputs
| Output | Type | Description |
| -------------- | ------ | ---------------------------------------------------- |
| **Message ID** | String | Gmail ID of the sent message. |
| **Thread ID** | String | Gmail ID of the conversation containing the message. |
## Example: send a generated report
Create the report file first, then configure **Send Email** with:
* **Recipients** — The project subscribers.
* **Body Type** — **HTML**.
* **Attachments** — The generated report file.
Store the returned **Message ID** if another action needs to refer to the sent
message.
## Troubleshooting
Each recipient and CC value must be a valid email address. Put each address
in its own list item.
Set **Body Type** to **HTML**. The default is plain text.
# Star Message
Source: https://learn.workflow.dog/reference/actions/gmail/star
Add Gmail's star to one message.
The **Star Message** action adds Gmail's built-in `STARRED` label to a message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to star. |
This action has no output. Use **Is Starred?** when a downstream branch needs
the current state as a boolean.
# Trash Message
Source: https://learn.workflow.dog/reference/actions/gmail/trash-message
Move one Gmail message to Trash.
The **Trash Message** action moves a Gmail message into Trash. It does not
permanently delete the message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to trash. |
This action returns no output. A trashed message can be restored with
**Untrash Message** while Gmail still retains it.
# Unmark as Important
Source: https://learn.workflow.dog/reference/actions/gmail/unmark-as-important
Remove Gmail's important marker from one message.
The **Unmark as Important** action removes Gmail's built-in `IMPORTANT` label
from a message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to update. |
This action changes the selected message and returns no output.
# Unstar Message
Source: https://learn.workflow.dog/reference/actions/gmail/unstar
Remove Gmail's star from one message.
The **Unstar Message** action removes Gmail's built-in `STARRED` label from a
message.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to unstar. |
This action changes the message and returns no output.
# Untrash Message
Source: https://learn.workflow.dog/reference/actions/gmail/untrash-message
Restore one Gmail message from Trash.
The **Untrash Message** action removes a Gmail message from Trash.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------- |
| **Third-party account** | Google account | Yes | Gmail account containing the message. |
| **Message ID** | String | Yes | Gmail ID of the message to restore. |
This action can restore a message that is still in Trash. It cannot recover a
message that Gmail has permanently deleted.
# Check Availability
Source: https://learn.workflow.dog/reference/actions/google-calendar/check-availability
Check whether a Google Calendar has any conflicts during a specific time.
The **Check Availability** action checks one calendar for busy periods between
two times. Use it before scheduling an event, offering an appointment, or
continuing a workflow only when a calendar is free.
## Quick start
Choose the Google account whose calendar you want to check.
Provide **Starting At** and **Ending At**, then choose the **Timezone** used
for the availability request.
Leave **Calendar ID** empty to check the account's primary calendar, or
enter another calendar's ID.
Route **Is Available?** into conditional logic. Inspect **Busy Periods**
when you need the exact conflicts.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------ |
| **Third-party account** | Google account | Yes | The Google account used to read free/busy information. |
| **Starting At** | Date | Yes | Beginning of the time window to check. |
| **Ending At** | Date | Yes | End of the time window to check. |
| **Calendar ID** | String | No | Calendar to check. Defaults to `primary`. |
| **Timezone** | Timezone string | Yes | Timezone supplied to Google for the free/busy query. |
## Outputs
| Output | Type | Description |
| ----------------- | -------------------- | -------------------------------------------------------------- |
| **Is Available?** | Boolean | `true` when Google returns no busy periods in the time window. |
| **Busy Periods** | List of busy periods | Conflicts, each with a **Start** and **End** date. |
Availability is based on busy periods from the selected calendar. The action
does not inspect other calendars attached to the account.
## Example: guard event creation
Connect the requested start and end times to **Check Availability**, then branch
on **Is Available?**:
* When `true`, create the calendar event.
* When `false`, use **Busy Periods** to prepare a message offering another time.
## Troubleshooting
**Calendar ID** defaults to the account's primary calendar. Supply the
intended calendar ID when checking a shared, team, or secondary calendar.
Confirm that the connected account can access the Calendar ID and that the
account still has a Calendar free/busy or read scope.
# Create Event
Source: https://learn.workflow.dog/reference/actions/google-calendar/create-event
Create an event in Google Calendar and optionally invite attendees.
The **Create Event** action adds a timed event to Google Calendar. It can set
the event's details, invite multiple attendees, and optionally send Google
Calendar notifications.
## Quick start
Choose a Google account with permission to create calendar events.
Set **Summary**, **Starting At**, **Ending At**, and **Timezone**. Add a
description or location when they help attendees.
Add one **Attendees** item for each email address that should be invited.
Pass **Event ID** to later Calendar actions or send **Event Link** to a
person who needs to open the event.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------------- | -------- | -------------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | The Google account that creates the event. |
| **Summary** | String | Yes | Event title. |
| **Starting At** | Date | Yes | Event start date and time. |
| **Ending At** | Date | Yes | Event end date and time. |
| **Description** | String | No | Additional event details. |
| **Location** | String | No | Physical or virtual location text. |
| **Attendees** | List of email strings | No | People to invite. Defaults to an empty list. |
| **Send Notifications** | Boolean | No | Whether Google emails attendees about the event. Defaults to `true`. |
| **Calendar ID** | String | No | Calendar that receives the event. Defaults to `primary`. |
| **Timezone** | Timezone string | Yes | Timezone attached to the event's start and end. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | --------------------------------------------- |
| **Event ID** | String | Google's identifier for the created event. |
| **Event Link** | String | Link that opens the event in Google Calendar. |
**Send Notifications** defaults to on. Turn it off before testing with real
attendee addresses if you do not want Google to email them.
## Example: schedule an approved request
After a meeting request is approved, check the requested time with **Check
Availability**. If the calendar is free, create the event and include the
returned **Event Link** in a confirmation email to the requester.
Use the same start, end, Calendar ID, and timezone for the availability check
and event creation so the event is written to the calendar you checked.
## Troubleshooting
Empty **Calendar ID** means the connected account's primary calendar. Supply
the target calendar ID for shared or secondary calendars.
Every attendee must be a valid email address. Remove names or surrounding
text and pass only the email address.
# Find Free Time
Source: https://learn.workflow.dog/reference/actions/google-calendar/find-free-time
Find open periods of a minimum length in a Google Calendar.
The **Find Free Time** action returns gaps between busy periods on one Google
Calendar. Use it to propose appointment windows, locate focus time, or search a
calendar before creating an event.
## Quick start
Set **Starting At** and **Ending At** to bound the search.
Enter the shortest useful slot in minutes. The default is `30`.
Leave **Calendar ID** empty for the primary calendar and select the
**Timezone** used for the free/busy request.
Use **Free Slots** as a list, or repeat the next workflow steps for each
slot's **Start** and **End**.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account used to read free/busy data. |
| **Starting At** | Date | Yes | Beginning of the search range. |
| **Ending At** | Date | Yes | End of the search range. |
| **Minimum Duration** | Number | No | Minimum slot length in minutes. Must be at least `1`; default `30`. |
| **Calendar ID** | String | No | Calendar to search. Defaults to `primary`. |
| **Timezone** | Timezone string | Yes | Timezone supplied to Google for the free/busy query. |
## Outputs
| Output | Type | Description |
| -------------- | ------------------ | ------------------------------------------------ |
| **Free Slots** | List of time slots | Open periods, each with a **Start** and **End**. |
The action sorts busy periods by start time, then returns qualifying open time
before the first conflict, between conflicts, and after the last conflict.
Slots shorter than **Minimum Duration** are omitted rather than shortened or
combined.
The output can be an empty list. That means the selected calendar has no
qualifying gap inside the requested range.
## Example: propose appointment options
Search the acceptable scheduling window, take the first three items from **Free
Slots**, and format their **Start** and **End** values into an availability
message. The recipient can then choose among those options.
## Troubleshooting
Check that **Ending At** is after **Starting At**, reduce **Minimum
Duration**, widen the search range, and verify the Calendar ID.
**Minimum Duration** is a filter, not a requested slot size. A two-hour
opening remains one two-hour slot even when the minimum is 30 minutes.
# Get Event
Source: https://learn.workflow.dog/reference/actions/google-calendar/get-event
Retrieve the details of one Google Calendar event.
The **Get Event** action loads one event by its Google Calendar event ID. Use it
when a workflow already has an event identifier and needs current event details,
attendees, links, or ownership information.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ----------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account used to read the event. |
| **Event ID** | String | Yes | Google's identifier for the event. |
| **Calendar ID** | String | No | Calendar containing the event. Defaults to `primary`. |
**Event ID** is available from **Create Event** and from each item returned by
**List Events**.
## Outputs
| Output | Type | Description |
| ---------------- | --------------- | --------------------------------------------------------------- |
| **Summary** | String | Event title. |
| **Description** | String | Event description, when present. |
| **Location** | String | Event location, when present. |
| **Start** | Date | Event start. |
| **End** | Date | Event end. |
| **Is All Day?** | Boolean | Whether Google represents the event without a start date-time. |
| **Status** | String | Google status such as `confirmed`, `tentative`, or `cancelled`. |
| **Event Link** | String | Link that opens the event in Google Calendar. |
| **Meeting Link** | String | Google Meet or Hangout link, when present. |
| **Attendees** | List of strings | Attendee email addresses. |
| **Creator** | String | Event creator's email address, when available. |
| **Organizer** | String | Event organizer's email address, when available. |
Some event fields may be empty because Google did not provide them. All-day
events still return **Start** and **End** as dates and set **Is All Day?** to
`true`.
## Example: send an event reminder
Pass a previously stored event ID to **Get Event**, then build the reminder from
the returned **Summary**, **Start**, **Meeting Link**, and **Event Link**. Empty
meeting links can be omitted when the event has no online meeting.
## Troubleshooting
Event IDs are resolved inside a calendar. Supply the same Calendar ID that
contains the event; leaving it blank searches the primary calendar.
Google only returns this value when the event has an associated Google Meet
or Hangout link.
# List Events
Source: https://learn.workflow.dog/reference/actions/google-calendar/list-events
List Google Calendar events in chronological order.
The **List Events** action retrieves events from one Google Calendar. Narrow the
results by time range and free-text query, then process the returned events as a
list or repeat over them one at a time.
## Quick start
Choose an account that can read the calendar.
Optionally provide **Starting At**, **Ending At**, or **Query**. Leave both
dates empty when you do not want a time bound.
Leave **Calendar ID** empty for the primary calendar. Set **Max Results**
between `1` and `250`; it defaults to `50`.
Connect the entire **Events** list or repeat downstream actions for each
event.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account used to read events. |
| **Starting At** | Date | No | Earliest event time to include. |
| **Ending At** | Date | No | Latest event time to include. |
| **Calendar ID** | String | No | Calendar to list. Defaults to `primary`. |
| **Max Results** | Number | No | Maximum returned events, from `1` to `250`. Defaults to `50`. |
| **Query** | String | No | Free-text terms passed to Google Calendar search. |
| **Timezone** | Timezone string | Yes | Timezone supplied with the Calendar request. |
## Outputs
**Events** is a list ordered by start time. Recurring events are expanded into
individual occurrences.
| Event field | Type | Description |
| ---------------- | ------- | ----------------------------------------------------------- |
| **ID** | String | Unique event identifier. |
| **Summary** | String | Event title. |
| **Description** | String | Event description, when present. |
| **Location** | String | Event location, when present. |
| **Start** | Date | Event start. |
| **End** | Date | Event end. |
| **Is All Day?** | Boolean | Whether the event has a date rather than a date-time start. |
| **Status** | String | Status such as `confirmed`, `tentative`, or `cancelled`. |
| **Event Link** | String | Link to the event in Google Calendar. |
| **Meeting Link** | String | Google Meet or Hangout link, when present. |
| **Creator** | String | Creator email address, when available. |
| **Organizer** | String | Organizer email address, when available. |
This action returns one page of results only. If more events match than **Max
Results**, later matches are not included.
## Example: prepare a daily agenda
Set **Starting At** and **Ending At** to the beginning and end of the day, then
repeat over **Events**. Format each event's **Summary**, **Start**, and
**Meeting Link** into an agenda before sending the completed message.
## Troubleshooting
Verify the date boundaries, Calendar ID, Query, and **Max Results**. The
query uses Google Calendar's free-text search and can narrow the result set.
Recurring series are expanded into their individual occurrences so each
scheduled instance can be processed separately.
# Create Form
Source: https://learn.workflow.dog/reference/actions/google-forms/create-form
Create a blank Google Form with a title.
The **Create Form** action creates a new blank Google Form. Use it when a
workflow needs a fresh form whose questions or sharing settings will be managed
separately.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ---------------------------------------------- |
| **Third-party account** | Google account | Yes | The Google account that owns the new form. |
| **Title** | String | Yes | Title used for both the form and its document. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ----------------------------------------- |
| **Form ID** | String | Google's identifier for the created form. |
The action creates the form itself but does not add questions. Store **Form
ID** if later workflow steps or external tools need to configure it.
## Example: create a form for a new project
When a project is created, build a descriptive title such as *Project name
feedback* and pass it to **Create Form**. Store the returned **Form ID** with
the project so later steps can find and configure the correct form.
# Get Form Details
Source: https://learn.workflow.dog/reference/actions/google-forms/get-form
Retrieve metadata and settings for a Google Form.
The **Get Form Details** action retrieves one Google Form by ID or URL. Use it
to confirm a form's identity, read its titles and settings, or get the public
response URL.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account used to read the form. |
| **Form ID or URL** | String | Yes | A Google Form ID or a URL containing the form ID. |
The action accepts a direct ID. For a URL, it extracts the value after
`/forms/d/`.
Use the form's edit URL when you have one. The public responder URL is also
returned by the action for sharing with respondents.
## Outputs
| Output | Type | Description |
| ------------------ | ------ | -------------------------------------- |
| **Form ID** | String | Unique form identifier. |
| **Title** | String | Title displayed inside the form. |
| **Document Title** | String | Title of the Google Forms document. |
| **Settings** | Object | Form configuration returned by Google. |
| **Revision ID** | String | Current form revision identifier. |
| **Responder URI** | String | URL where people can submit responses. |
## Example: publish a response link
Retrieve the form using its stored ID, then add **Responder URI** to a
confirmation email. Recipients can use that URL to open the public form and
submit a response.
## Troubleshooting
Paste the direct ID or a standard Google Forms URL containing `/forms/d/`.
Confirm the connected Google account has access to the form.
Google stores the form's displayed title separately from the document title.
Choose the output that matches where you intend to show it.
# Chat
Source: https://learn.workflow.dog/reference/actions/google-genai/chat
Generate a text response with a Google Gemini model.
The Google Gemini **Chat** action sends one prompt and an optional system
instruction to a Gemini model. It returns the model's response as text.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| **Third-party account** | Google Generative AI account | Yes | The API key used for the request. |
| **Prompt** | String | Yes | The user request sent to Gemini. |
| **Model** | Enum | Yes | Gemini 2.5 Pro, 2.5 Flash, 2.0 Flash, 2.0 Flash Lite, 1.5 Pro, or 1.5 Flash. Defaults to Gemini 2.5 Flash. |
| **Temperature** | Number | No | Response randomness from `0` to `2`. Defaults to `1`. |
| **System Prompt** | String | No | Instructions that define role, style, or constraints. |
## Output
| Output | Type | Description |
| ------------ | ------ | -------------------------------- |
| **Response** | String | Gemini's complete text response. |
This action is stateless and text-only. Include all required context in the
current prompt, and use a separate action when you need image generation.
# Generate Image
Source: https://learn.workflow.dog/reference/actions/google-genai/generate-image
Create an image with a Google Gemini image model.
The Google Gemini **Generate Image** action returns one generated image file.
It supports a broad set of aspect ratios and model-dependent output
resolution.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------------- | --------- | --------------------------------------------------------------------------------- |
| **Third-party account** | Google Generative AI account | Yes | The API key used for generation. |
| **Prompt** | String | Yes | A description of the image to create. |
| **Model** | Enum | Yes | Gemini 2.5 Flash Image or Gemini 3 Pro Image. Defaults to Gemini 2.5 Flash Image. |
| **Aspect Ratio** | Enum | Yes | `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, or `21:9`. |
| **Image Size** | Enum | Sometimes | `1K`, `2K`, or `4K`; shown only for Gemini 3 Pro Image. Defaults to `2K`. |
## Output
| Output | Type | Description |
| --------- | ---- | ---------------------------------------------------------- |
| **Image** | File | The generated image with the MIME type returned by Gemini. |
WorkflowDog makes up to three generation attempts when Gemini returns no image
data. The action fails if all attempts produce no image.
Pick the aspect ratio for the destination first—such as `9:16` for a story or
`16:9` for a banner—then describe composition with that frame in mind.
# Append Values to Range
Source: https://learn.workflow.dog/reference/actions/google-sheets/append-values
Append one or more rows at the end of a Google Sheets data range.
The **Append Values to Range** action adds rows after the existing data found
within an A1 range. Google inserts rows and treats values as user-entered input.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | -------------- | -------- | ------------------------------------------------ |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet to update. |
| **Range** | String | Yes | A1 table range, such as `Sheet1!A:B`. |
| **Rows** | List of lists | Yes | Rows of string or numeric cell values to append. |
## Outputs
| Output | Type | Description |
| ----------------- | ------ | --------------------------------------------- |
| **Updated Range** | String | A1 range occupied by the newly appended rows. |
Appended rows take on the table's existing formatting behavior. The range
tells Google where to detect the table; it is not necessarily the exact output
range.
## Example
For each new order, build a row containing the order ID, customer, and total,
then append it to `Orders!A:C`. Store **Updated Range** if later actions need to
locate the cells that were added.
# Create Range from Parts
Source: https://learn.workflow.dog/reference/actions/google-sheets/build-range
Build Google Sheets A1 notation from row and column components.
The **Create Range from Parts** action constructs an A1 range string without
calling Google. It accepts column letters or one-based column numbers and
automatically quotes sheet names containing punctuation or spaces.
## Inputs
| Input | Type | Required | Description |
| ---------------- | ---------------- | -------- | ------------------------------------------------------ |
| **Sheet Name** | String | No | Sheet qualifier to place before `!`. |
| **Start Column** | String or number | Yes | Starting column, such as `A` or `1`. |
| **Start Row** | Number | No | Starting row. Omit for a full-column range. |
| **End Column** | String or number | No | Ending column. Omit with End Row for a single address. |
| **End Row** | Number | No | Ending row. |
## Outputs
| Output | Type | Description |
| --------- | ------ | ------------------------------- |
| **Range** | String | Constructed A1 notation string. |
## Examples
| Parts | Result |
| ----------------------------------------- | --------------------- |
| Start Column `1`, Start Row `2` | `A2` |
| Start Column `A`, End Column `C` | `A:C` |
| Sheet `Sales 2026`, Start `A1`, End `D20` | `'Sales 2026'!A1:D20` |
Use this action when row or column bounds come from earlier steps, then pass
**Range** to Read, Write, Clear, or Highlight Range.
# Clear Range
Source: https://learn.workflow.dog/reference/actions/google-sheets/clear-range
Remove values from a Google Sheets range without deleting its cells.
The **Clear Range** action removes cell values from an A1 range. It does not
delete rows, columns, or the sheet itself.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | -------------- | -------- | ------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet to update. |
| **Range** | String | Yes | A1 range to clear, such as `Sheet1!A2:D20`. |
Clearing values preserves the range's structure and formatting. Use **Delete
Row(s)** when subsequent rows should shift upward.
This action returns no output. Double-check dynamically built ranges before
clearing them.
# Create Sheet
Source: https://learn.workflow.dog/reference/actions/google-sheets/create-sheet
Add a blank sheet to an existing Google Spreadsheet.
The **Create Sheet** action adds a blank tab to an existing spreadsheet. Use
**Create Table** instead when the new sheet should also receive column headers.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | -------------- | -------- | --------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access to the spreadsheet. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet that receives the sheet. |
| **Sheet Name** | String | Yes | Title for the new sheet tab. |
This action returns no output. Use **Get Spreadsheet Details** after creation
if you need the new sheet's numeric ID.
## Troubleshooting
Sheet titles must be unique within a spreadsheet. Choose a different name or
write to the existing sheet.
# Create Spreadsheet
Source: https://learn.workflow.dog/reference/actions/google-sheets/create-spreadsheet
Create a new Google Spreadsheet.
The **Create Spreadsheet** action creates a new Google Sheets file owned by the
connected account.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ----------------------------------------- |
| **Third-party account** | Google account | Yes | Google account that owns the spreadsheet. |
| **Title** | String | Yes | Title of the new spreadsheet. |
## Outputs
| Output | Type | Description |
| ------------------- | ------ | ---------------------------------------- |
| **Spreadsheet ID** | String | Google's identifier for the spreadsheet. |
| **Spreadsheet URL** | String | URL that opens the spreadsheet. |
Use either output as **Spreadsheet ID or URL** in later Google Sheets actions.
## Example
When a new client is added:
1. Create a spreadsheet for the client.
2. Connect **Spreadsheet ID** to **Create Table** to initialize its columns.
3. Store **Spreadsheet URL** wherever your team tracks client resources.
# Create Table
Source: https://learn.workflow.dog/reference/actions/google-sheets/create-table
Create a new sheet with headers and optional header formatting.
The **Create Table** action creates a new sheet and writes a header row. It can
format the headers and freeze all rows through the selected header row.
## Inputs
| Input | Type | Required | Description |
| --------------------------- | --------------- | -------- | ----------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet that receives the new sheet. |
| **Sheet Name** | String | Yes | New sheet tab name. |
| **Headers** | List of strings | Yes | One or more column headers, written from column A. |
| **Header Row Number** | Number | No | One-based row containing headers. Defaults to `1`. |
| **Apply Header Formatting** | Boolean | No | Add bold text, light-gray fill, and cell borders. Default `true`. |
| **Freeze Header Row** | Boolean | No | Freeze rows through the header row. Defaults to `true`. |
If **Header Row Number** is `3` and freezing is enabled, rows 1 through 3 are
frozen—not only row 3.
This action creates a new sheet every time it runs and has no output. It
cannot add table headers to an existing sheet.
## Troubleshooting
Use the same **Header Row Number** in later table actions. Those actions
default to row `1`.
# Delete Row(s)
Source: https://learn.workflow.dog/reference/actions/google-sheets/delete-row
Delete one or more numbered rows from a Google Sheet.
The **Delete Row(s)** action removes complete rows from a sheet. Cells below
the deleted rows shift upward.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | --------------- | -------- | -------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the rows. |
| **Sheet Name** | String | Yes | Exact sheet tab title. |
| **Row Numbers** | List of numbers | Yes | One-based row numbers to delete. |
Row numbers are deduplicated and grouped into consecutive ranges before the
request is sent.
This action deletes entire rows, including cells outside a logical table, and
returns no output. Row numbers refer to the sheet before the deletion request.
## Troubleshooting
Row numbers are absolute sheet positions, starting at `1`; they are not
relative to the configured header row.
# Delete Sheet
Source: https://learn.workflow.dog/reference/actions/google-sheets/delete-sheet
Delete a sheet tab from a Google Spreadsheet.
The **Delete Sheet** action permanently removes one sheet tab and its cell data
from a spreadsheet.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | -------------- | -------- | ----------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the sheet. |
| **Sheet Name** | String | Yes | Exact title of the sheet to delete. |
This action deletes the entire sheet and returns no output. Use **Clear
Range** when you only want to remove cell values.
## Troubleshooting
Sheet-name matching is exact. Use **Get Spreadsheet Details** to inspect the
available titles.
# Find Table Row(s) by Column
Source: https://learn.workflow.dog/reference/actions/google-sheets/find-rows-by-column
Find Google Sheets table rows using one or more typed column filters.
The **Find Table Row(s) by Column** action filters a header-based table and
returns either the first match or every matching row. Multiple filters use AND
logic: a row must satisfy all of them.
## Inputs
| Input | Type | Required | Description |
| --------------------------- | --------------- | -------- | -------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with read access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the table. |
| **Sheet Name** | String | Yes | Sheet tab to search. |
| **Filters** | List of filters | Yes | One or more column comparisons. |
| **Find Multiple Rows?** | Boolean | No | Return every match instead of only the first. Default `false`. |
| **Header Row Number** | Number | No | One-based header position. Defaults to `1`. |
| **Return Formatted Values** | Boolean | No | Format returned row values. Comparisons always use raw values. |
Each filter has a **Column Name**, **Match Mode**, and—when required—a **Search
Value**. Column names resolve to the closest header ignoring capitalization,
within a small spelling distance.
### Match modes
| Mode | Behavior |
| ------------------------------ | -------------------------------------------------------- |
| **Exact Value** | Loosely compares strings, numbers, or booleans. |
| **Empty** / **Not Empty** | Checks for `null`, missing, or empty-string values. |
| **Contains Text** | Case-insensitive substring match. |
| **Matches Regex** | Tests the string representation with the supplied regex. |
| **Greater/Less Than** variants | Compare raw numeric cells only. |
| **Is True** / **Is False** | Match actual boolean values. |
| **Is Truthy** / **Is Falsy** | Test the raw value's truthiness. |
## Outputs
**Found** is always available. Other outputs depend on **Find Multiple Rows?**:
\| Output | Type | Description | | -------------- | ------ |
\-------------------------------------------- | | **Found** | Boolean|
Whether a match exists. | | **Row Data** | Object | First matching row, or
empty when not found. | | **Row Number** | Number | One-based sheet row, or
empty when not found. |
\| Output | Type | Description | | --------------- | --------------- |
\------------------------------------- | | **Found** | Boolean | Whether any
match exists. | | **Rows** | List of objects | All matching rows. | | **Row
Numbers** | List of numbers | Corresponding one-based row numbers. |
Switching **Find Multiple Rows?** changes the node's output shape. Recheck
downstream connections after toggling it.
## Example: find unpaid large invoices
Add two filters:
* **Status** → **Exact Value** → `Unpaid`
* **Amount** → **Greater Than** → `1000`
Then pass **Row Numbers** to **Update Table Row(s)** or **Delete Row(s)**.
## Troubleshooting
Verify **Header Row Number** and inspect the header cells. The action allows
small spelling differences but cannot infer unrelated names.
Numeric modes only match raw numeric cells. A number stored as text does not
qualify, even if its displayed characters look numeric.
# Get First N Table Rows
Source: https://learn.workflow.dog/reference/actions/google-sheets/get-first-n-table-rows
Read the first N data rows below a Google Sheets header.
The **Get First N Table Rows** action reads rows immediately below a table's
header and returns them as objects keyed by the header values.
## Inputs
| Input | Type | Required | Description |
| --------------------------- | -------------- | -------- | ----------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with read access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the table. |
| **Sheet Name** | String | Yes | Sheet tab to read. |
| **Number of Rows** | Number | Yes | Maximum rows to read; must be at least `1`. |
| **Header Row Number** | Number | No | One-based header position. Defaults to `1`. |
| **Return Formatted Values** | Boolean | No | Return display text instead of raw values. Default `false`. |
## Outputs
| Output | Type | Description |
| -------- | ------------------- | ------------------------------------------- |
| **Rows** | List of row objects | First available data rows keyed by headers. |
The header row is not included. If fewer populated rows exist in the requested
range, the output list is shorter.
# Get Last N Table Rows
Source: https://learn.workflow.dog/reference/actions/google-sheets/get-last-n-table-rows
Read the last N populated rows from a Google Sheets table.
The **Get Last N Table Rows** action finds the end of a table and returns up to
the requested number of final data rows as header-keyed objects.
## Inputs
| Input | Type | Required | Description |
| --------------------------- | -------------- | -------- | ------------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with Sheets write access, required to locate the table end. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the table. |
| **Sheet Name** | String | Yes | Sheet tab to read. |
| **Number of Rows** | Number | Yes | Maximum rows to return; must be at least `1`. |
| **Header Row Number** | Number | No | One-based header position. Defaults to `1`. |
| **Return Formatted Values** | Boolean | No | Return display text instead of raw values. Default `false`. |
## Outputs
| Output | Type | Description |
| -------- | ------------------- | -------------------------------------- |
| **Rows** | List of row objects | Final table rows keyed by header text. |
The header row is excluded. If the table has fewer than N data rows, all
available rows are returned.
The action determines the append position using column A. Tables should have
consistent data in their first column for reliable end-of-table detection.
# Get Spreadsheet Details
Source: https://learn.workflow.dog/reference/actions/google-sheets/get-spreadsheet
Retrieve a Google Spreadsheet's title, URL, ID, and sheets.
The **Get Spreadsheet Details** action reads workbook-level metadata without
loading cell data. Use it to validate a spreadsheet or discover the sheets it
contains.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | -------------- | -------- | ---------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account used to read the spreadsheet. |
| **Spreadsheet ID or URL** | String | Yes | Direct spreadsheet ID or standard Google Sheets URL. |
## Outputs
| Output | Type | Description |
| ------------------ | -------------- | --------------------------------- |
| **Spreadsheet ID** | String | Unique spreadsheet identifier. |
| **Title** | String | Spreadsheet title. |
| **URL** | String | URL that opens the spreadsheet. |
| **Sheets** | List of sheets | Sheet metadata in workbook order. |
Each **Sheets** item contains:
| Field | Type | Description |
| ------------ | ------ | ------------------------------------------------ |
| **Sheet ID** | String | Numeric Google sheet ID represented as a string. |
| **Title** | String | Sheet tab name. |
| **Index** | Number | Zero-based position of the sheet tab. |
A spreadsheet is the whole file; a sheet is one tab inside it. Most table and
row actions expect a sheet title, not the numeric Sheet ID.
# Get Table Row(s)
Source: https://learn.workflow.dog/reference/actions/google-sheets/get-table-row
Read numbered Google Sheets rows as objects keyed by column headers.
The **Get Table Row(s)** action reads specific absolute row numbers and turns
each row into an object whose keys come from the table's header row.
## Inputs
| Input | Type | Required | Description |
| --------------------------- | --------------- | -------- | ------------------------------------------------------------ |
| **Third-party account** | Google account | Yes | Account with read access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the table. |
| **Sheet Name** | String | Yes | Sheet tab to read. |
| **Row Numbers** | List of numbers | Yes | One-based absolute sheet rows. |
| **Header Row Number** | Number | No | One-based header position. Defaults to `1`. |
| **Return Formatted Values** | Boolean | No | Return display text rather than raw values. Default `false`. |
## Outputs
| Output | Type | Description |
| -------- | ------------------- | --------------------------------------------- |
| **Rows** | List of row objects | Requested rows keyed by their column headers. |
Missing cell values become `null`. Duplicate row numbers are read once, and
the result is returned in ascending row order.
The output does not include row numbers. Keep the input list when later
actions need to update or delete the same positions.
# Get Table Row Range(s)
Source: https://learn.workflow.dog/reference/actions/google-sheets/get-table-row-range
Read one or more inclusive row ranges as table objects.
The **Get Table Row Range(s)** action reads inclusive row-number ranges and maps
their cells to table headers.
## Inputs
| Input | Type | Required | Description |
| --------------------------- | -------------- | -------- | ----------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with read access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the table. |
| **Sheet Name** | String | Yes | Sheet tab to read. |
| **Row Ranges** | List of ranges | Yes | **Start Row** and inclusive **End Row** for each range. |
| **Header Row Number** | Number | No | One-based header position. Defaults to `1`. |
| **Return Formatted Values** | Boolean | No | Return display text instead of raw values. Default `false`. |
Every row number is one-based and absolute within the sheet. An end row smaller
than its start row is rejected.
## Outputs
| Output | Type | Description |
| ------------- | ------------------- | --------------------------------------------------- |
| **Row Count** | Number | Number of rows actually returned. |
| **Rows** | List of row objects | Rows keyed by header text, flattened across ranges. |
The result can contain fewer rows than requested when the sheet has no values
for some positions.
## Troubleshooting
Reverse the bounds for the affected range. Both endpoints are inclusive.
# Highlight Range
Source: https://learn.workflow.dog/reference/actions/google-sheets/highlight-range
Set the background color of a Google Sheets range.
The **Highlight Range** action changes the background color of every cell in an
A1 range.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | -------------- | -------- | ------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet to format. |
| **Range** | String | Yes | A1 range, such as `Sheet1!A1:B2`. |
| **Color** | Hex color | No | Six-digit `#RRGGBB` color. Defaults to `#FFD230`. |
When the range does not include a sheet name, the action formats the first
sheet in the spreadsheet.
This action changes only the cells' background color and returns no output. It
does not alter values, fonts, borders, or number formats.
## Troubleshooting
Use a hash followed by exactly six hexadecimal digits, such as `#98FB98`.
Three-digit shorthand and alpha-channel colors are not accepted.
# Insert Table Rows
Source: https://learn.workflow.dog/reference/actions/google-sheets/insert-table-rows
Append, insert, or overwrite rows using Google Sheets column headers.
The **Insert Table Rows** action maps named values to a sheet's headers, then
appends them or writes them at a specific row. It is easier to maintain than a
raw range write when a table's columns have meaningful names.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | ------------------- | -------- | ------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the table. |
| **Sheet Name** | String | Yes | Sheet tab containing the table. |
| **Rows** | List of row objects | Yes | Column/value pairs for each row. |
| **Header Row Number** | Number | No | One-based header position. Defaults to `1`. |
| **Row Number** | Number | No | One-based destination. Omit to append after existing data. |
| **Overwrite** | Boolean | No | With Row Number, replace cells instead of inserting new rows. |
For each row object, column names are matched to the closest header ignoring
capitalization, within a small spelling distance. Missing columns become empty
cells.
## Behavior by mode
Leave **Row Number** empty. Sheets appends the rows after its detected table
and returns the appended **Updated Range**.
Provide **Row Number** and leave **Overwrite** off. New sheet rows are
inserted at that position, shifting existing rows down.
Provide **Row Number** and enable **Overwrite**. Values replace cells in the
destination rows without shifting existing data.
## Outputs
| Output | Type | Description |
| ----------------- | ------ | ------------------------------- |
| **Updated Range** | String | A1 range written by the action. |
In insert and overwrite modes, values are written as strings. Missing column
values are written as empty strings across the table width.
## Troubleshooting
Confirm **Header Row Number** and the sheet name, then use column names
close to the visible header text.
# Parse Range
Source: https://learn.workflow.dog/reference/actions/google-sheets/parse-range
Split Google Sheets A1 notation into sheet, row, and column fields.
The **Parse Range** action converts A1 notation into structured fields without
calling Google Sheets.
## Inputs
| Input | Type | Required | Description |
| --------- | ------ | -------- | -------------------------------------------- |
| **Range** | String | Yes | A1 notation such as `Sheet1!A1:B2` or `A:C`. |
Input column letters must be uppercase and contain no more than three letters.
Quoted sheet names are accepted.
## Outputs
| Output | Type | Description |
| ----------------------- | ------- | ---------------------------------------------- |
| **Sheet Name** | String | Sheet qualifier, or empty when omitted. |
| **Start Column Letter** | String | Starting column letter. |
| **Start Column Number** | Number | One-based starting column number. |
| **Start Row** | Number | Starting row, or empty for full-column ranges. |
| **End Column Letter** | String | Ending column letter, when present. |
| **End Column Number** | Number | One-based ending column, when present. |
| **End Row** | Number | Ending row, when present. |
| **Is Single Cell?** | Boolean | Whether the notation identifies one cell. |
## Troubleshooting
Use uppercase A1 notation. Examples include `A1`, `A1:B20`, `A:C`, and
`'Sales Data'!B2:D10`.
# Read Range
Source: https://learn.workflow.dog/reference/actions/google-sheets/read-range
Read a Google Sheets range as rows or columns.
The **Read Range** action reads cell values from an A1 range. Choose whether
the outer output list represents rows or columns and whether values use their
display formatting.
## Inputs
| Input | Type | Required | Description |
| --------------------------- | ------------------- | -------- | -------------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with read access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet to read. |
| **Range** | String | Yes | A1 range, such as `Sheet1!A1:B20`. |
| **Major Dimension** | `Rows` or `Columns` | No | Structure of the outer list. Defaults to **Rows**. |
| **Return Formatted Values** | Boolean | No | Return display strings instead of raw values. Default `false`. |
## Outputs
| Output | Type | Description |
| ----------------------- | ------------- | ---------------------------------------------------- |
| **Rows** or **Columns** | List of lists | Cell values grouped by the selected major dimension. |
Formatted values preserve display text such as `$1,234.00` or a rendered date.
Raw values are better for numeric comparisons and calculations.
Sheets can omit trailing empty cells and rows from returned arrays. Do not
assume every inner list has the full requested width.
## Example
Set **Range** to `Sheet1!A2:D` and keep **Major Dimension** set to **Rows**.
Repeat over the returned **Rows** to process each row's cells individually.
# Update Table Row(s)
Source: https://learn.workflow.dog/reference/actions/google-sheets/update-table-row
Update selected columns in one or more numbered Google Sheets rows.
The **Update Table Row(s)** action writes the same set of named column values to
one or more rows. It resolves column names from a header row and leaves
unspecified columns unchanged.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | --------------- | -------- | ------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet containing the table. |
| **Sheet Name** | String | Yes | Sheet tab to update. |
| **Row Numbers** | List of numbers | Yes | One-based absolute row numbers. |
| **Values** | Object | Yes | Column/value pairs applied to every selected row. |
| **Header Row Number** | Number | No | One-based header position. Defaults to `1`. |
Column names are matched case-insensitively to the closest header within a
small spelling distance. Row numbers are sorted and deduplicated.
This action applies one **Values** object to every selected row and returns no
output. Use separate action runs when different rows need different values.
## Example
After finding the overdue rows, pass their row numbers to **Row Numbers** and
set **Values** to `{ "Status": "Overdue" }`. The action writes that status to
every selected row.
## Troubleshooting
Verify the header row and available header text. A blank or substantially
different column name cannot be resolved.
# Write Range
Source: https://learn.workflow.dog/reference/actions/google-sheets/write-range
Write user-entered values into a Google Sheets range.
The **Write Range** action replaces values in a specified A1 range. Values are
interpreted as if a person entered them in Google Sheets, so formulas and
recognized dates can be parsed by Sheets.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | ------------------- | -------- | ------------------------------------------------------- |
| **Third-party account** | Google account | Yes | Account with write access. |
| **Spreadsheet ID or URL** | String | Yes | Spreadsheet to update. |
| **Range** | String | Yes | A1 destination range. |
| **Major Dimension** | `Rows` or `Columns` | No | How the outer Values list is interpreted. Default Rows. |
| **Rows** or **Columns** | List of lists | Yes | Cell values arranged by the selected dimension. |
## Outputs
| Output | Type | Description |
| ----------------- | ------ | ------------------------------------ |
| **Updated Range** | String | A1 range actually updated by Google. |
This action writes over cells in the destination. Use **Append Values to
Range** or **Insert Table Rows** when existing data should move rather than be
replaced.
## Example
With **Major Dimension** set to **Rows**, this value:
```json theme={null}
[
["Name", "Status"],
["Avery", "Active"]
]
```
writes two rows and two columns starting at the first cell of **Range**.
# Close Window
Source: https://learn.workflow.dog/reference/actions/http/close-window
Return a small HTML response that asks the browser window to close.
**Close Window** responds with an HTML script that calls `window.close()` after
the page loads. It is available with **URL** and **Form Submission** triggers.
## Input
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ----------------------------------------------------------- |
| **Status** | Number | No | An HTTP status code from `100` to `599`. Defaults to `200`. |
This is useful at the end of popup-based authorization or handoff flows.
Browsers commonly allow scripts to close only windows that were opened by
script. A normal tab opened directly by the user may remain open.
# Make HTTP Request
Source: https://learn.workflow.dog/reference/actions/http/fetch
Call an external HTTP endpoint and use its body, status, and headers.
**Make HTTP Request** sends an outbound request to an external URL. Use it to
call REST APIs, submit data to web services, or retrieve text-based resources.
This action cannot call internal or private WorkflowDog URLs. Requests to
non-external addresses are rejected.
## Inputs
| Input | Type | Required | Description |
| -------------------- | ------------------------------------------ | ------------------------------ | ------------------------------------------------------------------------------------- |
| **URL** | String | Yes | The complete destination URL. |
| **Method** | `GET`, `POST`, `PUT`, `PATCH`, or `DELETE` | Yes | The HTTP method. Defaults to `GET`. |
| **Body** | String or file | For `POST`, `PUT`, and `PATCH` | The request payload. Its type follows **Content Type** when a known type is selected. |
| **Content Type** | String | No | The MIME type sent in the `Content-Type` header. |
| **Query Parameters** | List of name/value pairs | No | Parameters added to the URL. Existing parameters with the same name are replaced. |
| **Headers** | List of name/value pairs | No | Request headers. |
**Body** and **Content Type** are hidden for `GET` and `DELETE` requests.
### Body types
Known text types—including `application/json`, `text/plain`, `text/csv`, and
XML—use a string body. Known binary types—including `multipart/form-data`,
`application/pdf`, and common image types—use a file body. You can also enter a
custom MIME type; in that case the body accepts any compatible value.
A header added under **Headers** takes precedence over the value generated by
**Content Type** when both use the same header name.
## Outputs
| Output | Type | Description |
| ------------ | ----------------- | ------------------------------------------------------------------ |
| **Response** | String | The complete response body read as text. |
| **Status** | Number | The HTTP status code, such as `200` or `404`. |
| **Headers** | Object of strings | Response headers. Select individual header properties when needed. |
The action returns normally for non-success status codes. Branch on **Status**
when a workflow must treat `4xx` or `5xx` responses differently.
## Example: send JSON to an API
Set **Method** to `POST`, **Content Type** to `application/json`, and connect a
JSON string to **Body**:
```json theme={null}
{
"email": "ada@example.com",
"plan": "pro"
}
```
Add authentication under **Headers**, then use **Status** to confirm whether
the service accepted the request.
## Troubleshooting
Use a complete public URL, including `https://`. Internal, loopback, and
private destinations are blocked.
**Response** is always read as text. Use an integration that returns a file
when the response must preserve raw bytes.
Confirm that **Content Type** matches the actual payload. Selecting
`application/json` does not serialize an object automatically; **Body** must
already be a JSON string.
# Redirect
Source: https://learn.workflow.dog/reference/actions/http/redirect
Redirect an HTTP caller to another URL.
**Redirect** finishes an HTTP-triggered workflow with a `Location` header. It is
available with **URL**, **Form Submission**, and **Webhook** triggers.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | --------------------------------------------------------- |
| **URL** | String | Yes | The absolute destination URL. |
| **Status** | Number | No | A redirect status from `300` to `399`. Defaults to `302`. |
Use `302` for a temporary redirect or `301` for a permanent redirect. Choose
`307` or `308` when the caller must preserve its original request method.
Permanent redirects can be cached by browsers and intermediaries. Use `302`
while testing a workflow.
# Respond Text
Source: https://learn.workflow.dog/reference/actions/http/respond
Finish an HTTP-triggered workflow with a text response.
**Respond Text** sends a string back to the client that started the workflow.
It is available in workflows using the **URL**, **Form Submission**, or
**Webhook** trigger.
## Inputs
| Input | Type | Required | Description |
| ---------------- | ------ | -------- | ------------------------------------------------------------------------- |
| **Body** | String | Yes | The response body. |
| **Status** | Number | No | An HTTP status code from `100` to `599`. Defaults to `200`. |
| **Content Type** | Enum | Yes | `text/plain`, `text/html`, or `application/json`. Defaults to plain text. |
**Content Type** describes the string; it does not transform it. If you select
JSON, **Body** must already contain valid JSON.
This action ends the waiting HTTP response. Place it on every branch that
should return a deliberate result to the caller.
# Respond File
Source: https://learn.workflow.dog/reference/actions/http/respond-file
Return a file for display or download from an HTTP workflow.
**Respond File** sends a file back to a **URL** or **Form Submission** caller.
The response uses the file's MIME type.
## Inputs
| Input | Type | Required | Description |
| ------------------- | ------------------------ | -------- | --------------------------------------------------------------------------------- |
| **File** | File | Yes | The file to return. |
| **Status** | Number | No | An HTTP status code from `100` to `599`. Defaults to `200`. |
| **Send Content As** | `Inline` or `Attachment` | Yes | Whether the browser should display the file or download it. Defaults to `Inline`. |
Use **Inline** for browser-viewable content such as images or PDFs. Use
**Attachment** to send a download; the response includes the file's name.
Browser behavior still depends on the file type and the caller's browser
settings.
# Respond HTML
Source: https://learn.workflow.dog/reference/actions/http/respond-html
Return an HTML document from a URL or form workflow.
**Respond HTML** returns a string with the `text/html` content type. It is
available with the **URL** and **Form Submission** triggers.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ----------------------------------------------------------- |
| **Body** | String | Yes | The HTML document or fragment to return. |
| **Status** | Number | No | An HTTP status code from `100` to `599`. Defaults to `200`. |
```html theme={null}
Thanks — your submission was received.
```
The HTML is sent as provided. Only include markup and scripts you trust.
# Respond JSON
Source: https://learn.workflow.dog/reference/actions/http/respond-json
Serialize a value as JSON and return it to an HTTP caller.
**Respond JSON** serializes any connected value and returns it with an
`application/json` content type. It works with the **URL**, **Form Submission**,
and **Webhook** triggers.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------- | -------- | ----------------------------------------------------------- |
| **Body** | Any | Yes | The value to serialize. |
| **Status** | Number | No | An HTTP status code from `100` to `599`. Defaults to `200`. |
| **Pretty** | Boolean | No | Adds two-space indentation to the JSON. Defaults to on. |
## Example
Connect an object containing `ok` and `orderId` to **Body**. The caller receives:
```json theme={null}
{
"ok": true,
"orderId": "ord_123"
}
```
Turn **Pretty** off for smaller production responses. Formatting changes
whitespace only, not the returned data.
# Respond Status
Source: https://learn.workflow.dog/reference/actions/http/respond-status
Finish an HTTP request with a status code and no custom body.
**Respond Status** returns only an HTTP status. It works with **URL**,
**Form Submission**, and **Webhook** triggers.
## Input
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ----------------------------------------------------- |
| **Status** | Number | No | A status code from `100` to `599`. Defaults to `200`. |
Use this action for acknowledgements such as `204`, authorization failures such
as `401`, or not-found responses such as `404`.
Because no custom body is supplied, the HTTP server may include the standard
status text associated with the selected code.
# Adjust Colors
Source: https://learn.workflow.dog/reference/actions/images/adjust-colors
Change an image's brightness, saturation, contrast, and hue.
**Adjust Colors** applies four color adjustments to an image in one pass.
Unchanged settings default to zero, so you can adjust only the properties you
need.
## Inputs
| Input | Type | Required | Description |
| -------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------- |
| **Image** | File | Yes | The image to adjust. |
| **Brightness** | Number | No | From `-100` to `100`. Negative values darken; positive values brighten. Defaults to `0`. |
| **Saturation** | Number | No | From `-100` to `100`. Negative values reduce color intensity; positive values increase it. Defaults to `0`. |
| **Contrast** | Number | No | From `-100` to `100`. Negative values flatten tonal differences; positive values increase them. Defaults to `0`. |
| **Hue** | Number | No | Hue rotation from `0` to `360` degrees. Defaults to `0`. |
## Output
| Output | Type | Description |
| ------------------ | ---- | -------------------------------------------------------------------- |
| **Adjusted Image** | File | The processed image, preserving the input file's name and MIME type. |
Adjustments are combined before the result is encoded. Reusing one node for
several changes avoids repeatedly decoding and encoding the same image.
Make small adjustments first. Extreme brightness, saturation, or contrast
values can permanently clip details in the output.
# Blur Image
Source: https://learn.workflow.dog/reference/actions/images/blur
Apply a configurable Gaussian blur to an image.
**Blur Image** softens an image with a Gaussian blur.
| Direction | Field | Type | Description |
| --------- | ----------------- | ------ | ----------------------------------------------------------- |
| Input | **Image** | File | The image to blur. |
| Input | **Blur Amount** | Number | Blur strength from `0` to `1000`. Defaults to `5`. |
| Output | **Blurred Image** | File | The blurred image, preserving the input name and MIME type. |
Values below `0.3`, including `0`, return the original file unchanged. Larger
values create progressively stronger blur, with processing capped at `1000`.
A modest blur is usually enough for soft backgrounds. Use much larger values
when the goal is to obscure rather than style image content.
# Convert Image Format
Source: https://learn.workflow.dog/reference/actions/images/convert-format
Convert an image to JPEG, PNG, WebP, AVIF, or TIFF.
**Convert Image Format** decodes an image and re-encodes it in a selected image
format. The output filename receives the new extension.
## Inputs
| Input | Type | Required | Description |
| ----------- | ---------------------------------------- | -------- | ------------------------------------------ |
| **Image** | File | Yes | The source image. |
| **Format** | `jpeg`, `png`, `webp`, `avif`, or `tiff` | Yes | Target encoding. Defaults to `jpeg`. |
| **Quality** | Number | No | Value from `1` to `100`. Defaults to `90`. |
**Quality** controls lossy quality for JPEG, WebP, AVIF, and TIFF. For PNG, it
is translated into a compression level: lower quality values request more
compression, but do not intentionally discard pixels in the way JPEG does.
## Output
| Output | Type | Description |
| ------------------- | ---- | ------------------------------------------------- |
| **Converted Image** | File | The re-encoded image with the selected extension. |
The current output file may retain the input image's MIME type even though its
filename and bytes use the new format. When a downstream service relies
strictly on MIME metadata, verify what it receives.
Choose PNG when transparency or lossless pixels matter, JPEG for broadly
compatible photographs, and WebP or AVIF when smaller modern web assets are
more important.
# Crop Image
Source: https://learn.workflow.dog/reference/actions/images/crop
Extract a rectangular region from an image by pixel coordinates.
**Crop Image** extracts a rectangle from an image. Coordinates start at the
source image's top-left corner.
| Direction | Field | Type | Description |
| --------- | ----------------- | -------------------- | -------------------------------------------------------------- |
| Input | **Image** | File | The source image. |
| Input | **Left** | Non-negative integer | Pixels from the source's left edge to the crop's left edge. |
| Input | **Top** | Non-negative integer | Pixels from the source's top edge to the crop's top edge. |
| Input | **Width** | Positive integer | Width of the crop rectangle in pixels. |
| Input | **Height** | Positive integer | Height of the crop rectangle in pixels. |
| Output | **Cropped Image** | File | The extracted region, preserving the input name and MIME type. |
The full rectangle must fit inside the source image:
```text theme={null}
left + width ≤ source width
top + height ≤ source height
```
Use **Get Image Dimensions** before this action when crop coordinates are
calculated dynamically.
The action fails when the requested rectangle extends beyond the image
boundary. It does not pad or clamp the crop automatically.
# Flip Image
Source: https://learn.workflow.dog/reference/actions/images/flip
Mirror an image horizontally, vertically, or in both directions.
**Flip Image** mirrors an image across either axis.
| Direction | Field | Type | Description |
| --------- | ----------------- | ------- | ------------------------------------------------------------- |
| Input | **Image** | File | The image to flip. |
| Input | **Horizontal** | Boolean | Mirrors left to right. Defaults to on. |
| Input | **Vertical** | Boolean | Mirrors top to bottom. Defaults to off. |
| Output | **Flipped Image** | File | The processed image, preserving the input name and MIME type. |
Enable both toggles to mirror across both axes, which is equivalent to a
180-degree rotation. If both are off, the image is reprocessed without a flip.
# Generate Gradient
Source: https://learn.workflow.dog/reference/actions/images/generate-gradient
Create a linear or radial gradient image from a list of colors.
**Generate Gradient** creates a new image without requiring an input file.
Supply one or more colors, choose a gradient type, and set the output
dimensions and format.
## Inputs
| Input | Type | Required | Description |
| --------------- | ------------------------ | -------------------- | ----------------------------------------------------- |
| **Width** | Positive number | Yes | Output width in pixels. Defaults to `800`. |
| **Height** | Positive number | Yes | Output height in pixels. Defaults to `600`. |
| **Type** | `linear` or `radial` | Yes | Gradient geometry. Defaults to `linear`. |
| **Angle** | Number | For linear gradients | Direction from `0` to `360` degrees. Defaults to `0`. |
| **Color Stops** | List of strings | Yes | One or more colors. Two entries are shown by default. |
| **Format** | `png`, `jpeg`, or `webp` | Yes | Output encoding. Defaults to `png`. |
Color stops are placed at even intervals. With three colors, for example, they
appear at `0%`, `50%`, and `100%`. A single color produces a solid fill rather
than a gradient.
Use CSS-compatible color strings such as `#ff006e`. Linear angles are
normalized to one full rotation before rendering. **Angle** is hidden for a
radial gradient, which is centered in the image.
## Output
| Output | Type | Description |
| ------------------ | ---- | ----------------------------------------------------------------------- |
| **Gradient Image** | File | The generated image, named `gradient-{type}-{width}x{height}.{format}`. |
JPEG and WebP are encoded at quality `90`. PNG uses its normal lossless
encoding.
## Example: make a three-color background
Set the size to `1600` by `900`, choose `linear`, set **Angle** to `135`, and
add these color stops in order:
```text theme={null}
#111827
#4f46e5
#ec4899
```
The colors are spaced evenly from the first edge of the gradient to the last.
# Get Image Dimensions
Source: https://learn.workflow.dog/reference/actions/images/get-dimensions
Read an image's pixel width, height, and aspect ratio.
**Get Image Dimensions** inspects an image without changing it.
| Direction | Field | Type | Description |
| --------- | ---------------- | ------ | -------------------------------------------------------- |
| Input | **Image** | File | The image to inspect. |
| Output | **Width** | Number | Width in pixels. |
| Output | **Height** | Number | Height in pixels. |
| Output | **Aspect Ratio** | Number | Width divided by height, rounded to four decimal places. |
Use the outputs to calculate safe crop coordinates, choose portrait or
landscape branches, or resize an image relative to its original dimensions.
The action fails when the file cannot be decoded as an image or its dimensions
cannot be determined.
# Invert Colors
Source: https://learn.workflow.dog/reference/actions/images/invert
Create a color-negative version of an image.
**Invert Colors** replaces each color channel with its inverse while leaving
the alpha channel unchanged.
| Direction | Field | Type | Description |
| --------- | ------------------ | ---- | ------------------------------------------------------------------ |
| Input | **Image** | File | The image to invert. |
| Output | **Inverted Image** | File | The color-inverted image, preserving the input name and MIME type. |
Transparent pixels keep their transparency. Running the result through
**Invert Colors** a second time approximately restores the original colors,
subject to any encoding loss in the image format.
# Modify EXIF
Source: https://learn.workflow.dog/reference/actions/images/modify-exif
Strip or preserve image metadata and orientation information.
**Modify EXIF** controls which metadata is written into an image. Use it to
remove identifying metadata before sharing an image or to preserve metadata
when another image action would otherwise discard it.
## Inputs
| Input | Type | Required | Description |
| -------------------- | ------- | -------- | ------------------------------------------------------- |
| **Image** | File | Yes | The image to process. |
| **Action** | Enum | Yes | Metadata behavior. Defaults to `strip_all`. |
| **Keep Orientation** | Boolean | No | Available for `strip_keep_orientation`. Defaults to on. |
### Actions
| Action | Behavior |
| ------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `strip_all` | Writes the image without preserving its existing metadata. |
| `strip_keep_orientation` | Uses the orientation-specific path. **Keep Orientation** controls whether orientation metadata is retained. |
| `keep_all` | Preserves available metadata in the output. |
## Output
| Output | Type | Description |
| ------------------- | ---- | ------------------------------------------------------------- |
| **Processed Image** | File | The rewritten image, preserving the input name and MIME type. |
Metadata handling depends on what the image decoder can read and the output
format can store. Inspect the result when privacy or orientation is critical;
do not assume every metadata namespace is supported identically.
If the goal is privacy, use `strip_all` and verify the final file after all
other image actions have run. A later encoder may add fresh technical metadata.
# Overlay Images
Source: https://learn.workflow.dog/reference/actions/images/overlay
Scale and place a foreground image over a background image.
**Overlay Images** composites one image over another. The foreground is scaled
relative to the background, aligned to one of nine positions, and optionally
made translucent.
## Inputs
| Input | Type | Required | Description |
| -------------- | ------ | -------- | -------------------------------------------------------------------- |
| **Background** | File | Yes | The base image and the output canvas. |
| **Foreground** | File | Yes | The image placed over the background. |
| **Scale** | Number | No | Foreground scale from `0.01` to `1`. Defaults to `0.5`. |
| **Position** | Enum | No | One of nine top, center, or bottom alignments. Defaults to `center`. |
| **Opacity** | Number | No | Foreground opacity from `0` to `1`. Defaults to `1`. |
The node preserves the foreground's aspect ratio. At scale `1`, the foreground
is sized to fit the background along the limiting dimension; at `0.5`, that
fitted size is halved.
Available positions are:
```text theme={null}
top-left top-center top-right
center-left center center-right
bottom-left bottom-center bottom-right
```
## Output
| Output | Type | Description |
| ------------------- | ---- | ------------------------------------------------------------------- |
| **Composite Image** | File | The combined image, using the background file's name and MIME type. |
## Example: place a watermark
Use the source image as **Background**, a transparent logo as **Foreground**,
set **Scale** to a small value such as `0.15`, choose `bottom-right`, and lower
**Opacity** to `0.6`.
Positions align directly to an edge or corner; the action has no margin input.
Add transparent padding to the foreground first when the overlay needs inset
spacing.
## Troubleshooting
Scale is relative to the background's limiting dimension, not the
foreground's original size. Reduce **Scale**.
The output follows the background file's name and MIME type. Convert the
background before overlaying, or convert the composite afterward.
# Resize Image
Source: https://learn.workflow.dog/reference/actions/images/resize
Resize an image in pixels or as a percentage with configurable fit behavior.
**Resize Image** changes an image's dimensions. Provide either width, height,
or both; when only one dimension is present, the original aspect ratio is
preserved.
## Inputs
| Input | Type | Required | Description |
| -------------- | ------------------------ | ------------- | --------------------------------------------------------------------------- |
| **Image** | File | Yes | The image to resize. |
| **Unit** | `pixels` or `percentage` | Yes | How width and height are interpreted. Defaults to `pixels`. |
| **Width** | Positive number | No | Target width in pixels or as a percentage of original width. |
| **Height** | Positive number | No | Target height in pixels or as a percentage of original height. |
| **Fit** | Enum | Yes | How the source fits when both dimensions are supplied. Defaults to `cover`. |
| **Position** | Enum | Sometimes | Alignment for `cover` or `contain`. Defaults to `center`. |
| **Background** | String | For `contain` | Color used to fill empty space. Defaults to `#000000`. |
Percentage dimensions are converted from the source metadata and rounded down
to whole pixels. For example, width `50` means half of the original width.
### Fit modes
| Fit | Behavior |
| --------- | ------------------------------------------------------------------------------------------ |
| `cover` | Fills both target dimensions, cropping overflow as needed. |
| `contain` | Fits the whole image inside the target and fills remaining space with **Background**. |
| `fill` | Stretches the image to exactly the requested dimensions, even if the aspect ratio changes. |
| `inside` | Preserves aspect ratio and stays within both target dimensions. |
| `outside` | Preserves aspect ratio while meeting or exceeding both target dimensions. |
**Position** offers top, bottom, left, right, corner, and center alignment for
the crop or padding created by `cover` and `contain`.
## Output
| Output | Type | Description |
| ----------------- | ---- | ----------------------------------------------------------- |
| **Resized Image** | File | The resized image, preserving the input name and MIME type. |
## Examples
* Set width to `1200`, leave height empty, and use pixels to make a
1200-pixel-wide image without changing its proportions.
* Set width and height to `50` with percentage units to halve both dimensions.
* Set `1080` by `1080` with `cover` to create a square crop, or `contain` to
retain the whole source inside a square canvas.
If both width and height are empty, the action has no target size. Provide at
least one dimension for predictable output.
# Rotate Image
Source: https://learn.workflow.dog/reference/actions/images/rotate
Rotate an image clockwise and choose the color behind exposed corners.
**Rotate Image** rotates an image by any number of degrees. Positive angles
rotate clockwise.
| Direction | Field | Type | Description |
| --------- | ----------------- | ------ | ------------------------------------------------------------------- |
| Input | **Image** | File | The image to rotate. |
| Input | **Angle** | Number | Rotation in degrees. Defaults to `0`. |
| Input | **Background** | String | Color for newly exposed areas. Defaults to transparent `#00000000`. |
| Output | **Rotated Image** | File | The rotated image, preserving the input name and MIME type. |
Right-angle rotations rearrange the original pixels without exposed triangular
corners. Other angles expand the canvas and fill those corners with
**Background**.
Formats without alpha transparency cannot preserve a transparent background.
Choose an opaque color or convert to a transparency-capable format such as
PNG.
# Sharpen Image
Source: https://learn.workflow.dog/reference/actions/images/sharpen
Increase edge contrast with a configurable sharpening effect.
**Sharpen Image** emphasizes edges and fine detail.
| Direction | Field | Type | Description |
| --------- | ------------------- | ------ | ------------------------------------------------------------- |
| Input | **Image** | File | The image to sharpen. |
| Input | **Sharpness** | Number | Strength from `0` to `1000`. Defaults to `50`. |
| Output | **Sharpened Image** | File | The sharpened image, preserving the input name and MIME type. |
The displayed value is divided by `100` before processing. Values at or very
near zero return the original file unchanged; effective processing strength is
capped once the displayed value reaches `1000`.
Start below the default when sharpening compressed photographs. High values
can exaggerate noise, halos, and existing compression artifacts.
# Actions
Source: https://learn.workflow.dog/reference/actions/index
Reference documentation for every action available in WorkflowDog.
Actions are the steps that do work after a workflow starts. They can transform
values, call another service, make a decision, create a file, send a response,
or control which path runs next.
This reference documents every action currently available in the editor. Use
the navigation to browse by package, or search for the action by the name shown
in the node picker.
## Read an action page
Every page starts with the action's purpose, then documents the fields and
behavior that exist in the current implementation:
* **Inputs** are values the action reads. A field can be configured directly,
connected from an earlier output, or both, depending on the node.
* **Outputs** are values later actions can use. Some outputs appear only when a
related option is enabled.
* **Third-party account** identifies the connected service account used for an
external request.
* **Examples** show a representative configuration when the action benefits
from one.
* **Troubleshooting** calls out common failures and implementation-specific
constraints.
Many nodes change their visible inputs or outputs when a configuration value
changes. Review downstream connections after changing an option that controls
the node's shape.
## Static and connected values
Configuration fields are normally fixed for the workflow, while connectable
inputs can receive a different value on every run. Some fields support either
mode. Use a fixed value for behavior that should remain constant, and connect
an earlier output when the value belongs to the data being processed.
## Accounts and external services
Integration actions require a matching third-party account. The page for each
action describes the account type and the request it makes, but access still
depends on the permissions, API limits, and data available to that account.
When a service action fails, first verify the selected account, then inspect
required inputs and service-specific limits documented on that action's page.
## Actions and triggers
An action runs because the workflow reached it. A trigger starts a workflow in
response to an event or schedule. See the [Triggers reference](/reference/triggers)
for every available starting event.
# And
Source: https://learn.workflow.dog/reference/actions/logic/and
Return true only when every input is true.
| Input | Type | Required | Description |
| ---------- | ------------------ | -------- | ------------------- |
| **Values** | Repeatable Boolean | No | Values to evaluate. |
| Output | Type | Description |
| ---------- | ------- | ---------------------------------- |
| **Result** | Boolean | `true` when every value is `true`. |
The node starts with two value slots. If there are no values, the result is
`true`.
# Buffer
Source: https://learn.workflow.dog/reference/actions/logic/buffer
Pass a Boolean value through unchanged.
| Input | Type | Required | Description |
| --------- | ------- | -------- | -------------------------- |
| **Value** | Boolean | Yes | The value to pass through. |
| Output | Type | Description |
| ---------- | ------- | ------------------ |
| **Result** | Boolean | The input Boolean. |
Use Buffer as a simple connection point while organizing Boolean logic.
# Equals
Source: https://learn.workflow.dog/reference/actions/logic/equal
Check whether two values are strictly equal.
| Input | Type | Required | Description |
| ----- | ---- | -------- | ------------------------ |
| **A** | Any | Yes | First value to compare. |
| **B** | Any | Yes | Second value to compare. |
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------- |
| **Result** | Boolean | `true` when both values are strictly equal. |
Types must match: the number `1` does not equal the text `"1"`. Objects and
lists compare by identity, not by recursively comparing their contents.
# NAND
Source: https://learn.workflow.dog/reference/actions/logic/nand
Return false only when every input is true.
| Input | Type | Required | Description |
| ---------- | ------------------ | -------- | ------------------- |
| **Values** | Repeatable Boolean | No | Values to evaluate. |
| Output | Type | Description |
| ---------- | ------- | ---------------------------------------------- |
| **Result** | Boolean | The inverse of applying **And** to the values. |
For `[true, true]`, the result is `false`. If at least one value is `false`,
the result is `true`. With no values, the result is `false`.
# NOR
Source: https://learn.workflow.dog/reference/actions/logic/nor
Return true only when every input is false.
| Input | Type | Required | Description |
| ---------- | ------------------ | -------- | ------------------- |
| **Values** | Repeatable Boolean | No | Values to evaluate. |
| Output | Type | Description |
| ---------- | ------- | --------------------------------------------- |
| **Result** | Boolean | The inverse of applying **Or** to the values. |
The result is `false` as soon as any input is `true`. With no values, the
result is `true`.
# Not
Source: https://learn.workflow.dog/reference/actions/logic/not
Invert a Boolean value.
| Input | Type | Required | Description |
| --------- | ------- | -------- | -------------------- |
| **Value** | Boolean | Yes | The value to invert. |
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------- |
| **Result** | Boolean | `false` for `true`, and `true` for `false`. |
# Not Equals
Source: https://learn.workflow.dog/reference/actions/logic/not-equal
Check whether two values are not strictly equal.
| Input | Type | Required | Description |
| ----- | ---- | -------- | ------------------------ |
| **A** | Any | Yes | First value to compare. |
| **B** | Any | Yes | Second value to compare. |
| Output | Type | Description |
| ---------- | ------- | ---------------------------------------------- |
| **Result** | Boolean | `true` when the values are not strictly equal. |
Types matter: the number `1` and the text `"1"` are not equal. Objects and
lists compare by identity.
# Or
Source: https://learn.workflow.dog/reference/actions/logic/or
Return true when at least one input is true.
| Input | Type | Required | Description |
| ---------- | ------------------ | -------- | ------------------- |
| **Values** | Repeatable Boolean | No | Values to evaluate. |
| Output | Type | Description |
| ---------- | ------- | ----------------------------------------- |
| **Result** | Boolean | `true` when any supplied value is `true`. |
If there are no values, the result is `false`.
# XNOR
Source: https://learn.workflow.dog/reference/actions/logic/xnor
Return true when an even number of inputs are true.
| Input | Type | Required | Description |
| ---------- | ------------------ | -------- | ------------------- |
| **Values** | Repeatable Boolean | No | Values to evaluate. |
| Output | Type | Description |
| ---------- | ------- | --------------------------------------------- |
| **Result** | Boolean | `true` when the count of true values is even. |
`[true, true, false]` returns `true`; `[true, false, false]` returns `false`.
With no values, the true count is zero, so the result is `true`.
# XOR
Source: https://learn.workflow.dog/reference/actions/logic/xor
Return true when an odd number of inputs are true.
| Input | Type | Required | Description |
| ---------- | ------------------ | -------- | ------------------- |
| **Values** | Repeatable Boolean | No | Values to evaluate. |
| Output | Type | Description |
| ---------- | ------- | -------------------------------------------- |
| **Result** | Boolean | `true` when the count of true values is odd. |
`[true, false, false]` returns `true`; `[true, true, false]` returns `false`.
With no values, the result is `false`.
# Absolute Value
Source: https://learn.workflow.dog/reference/actions/math/absolute
Return a number's distance from zero.
The **Absolute Value** action removes a number's sign. Positive values and zero
stay unchanged; negative values become positive.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ----------------------- |
| **Number** | Number | Yes | The value to transform. |
## Outputs
| Output | Type | Description |
| ------------ | ------ | --------------------------------- |
| **Absolute** | Number | The absolute value of **Number**. |
For example, both `-12.5` and `12.5` produce `12.5`.
# Add
Source: https://learn.workflow.dog/reference/actions/math/add
Add two or more numbers.
The **Add** action sums a repeatable list of numbers in order. The node requires
at least two number inputs and can be expanded for additional values.
## Inputs
| Input | Type | Required | Description |
| ----------- | --------------- | -------- | -------------------------- |
| **Numbers** | List of numbers | Yes | Two or more values to add. |
## Outputs
| Output | Type | Description |
| ------- | ------ | ---------------------------------- |
| **Sum** | Number | The total of all supplied numbers. |
Empty repeat slots are treated as `0`. For example, `12`, `8`, and `-5`
produce `15`.
# Ceil
Source: https://learn.workflow.dog/reference/actions/math/ceil
Round a number upward to the nearest integer.
The **Ceil** action returns the smallest integer greater than or equal to the
input.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ------------------- |
| **Number** | Number | Yes | The value to round. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ------------------------------------------- |
| **Ceiled** | Number | The input rounded toward positive infinity. |
For example, `4.01` becomes `5`, while `-4.99` becomes `-4`.
# Clamp
Source: https://learn.workflow.dog/reference/actions/math/clamp
Keep a number between minimum and maximum limits.
The **Clamp** action constrains a number to a range. Values below **Min** become
the minimum, values above **Max** become the maximum, and values already inside
the range stay unchanged.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | -------------------------- |
| **Number** | Number | Yes | The value to constrain. |
| **Min** | Number | Yes | The minimum allowed value. |
| **Max** | Number | Yes | The maximum allowed value. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ----------------------------------- |
| **Clamped** | Number | The value constrained to the range. |
For a minimum of `0` and maximum of `100`, `-5` becomes `0`, `40` stays `40`,
and `125` becomes `100`.
Keep **Min** less than or equal to **Max**. Reversed bounds are applied in
sequence and produce the maximum bound rather than a conventional range.
# Cosine
Source: https://learn.workflow.dog/reference/actions/math/cos
Calculate the cosine of an angle in radians or degrees.
The **Cosine** action calculates the cosine of an angle.
## Inputs
| Input | Type | Required | Description |
| -------------- | ------------------ | -------- | ------------------------------------------------ |
| **Angle** | Number | Yes | The angle to evaluate. |
| **Angle Unit** | Radians or Degrees | Yes | How to interpret **Angle**. Defaults to radians. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ------------------------------ |
| **Result** | Number | The cosine of the input angle. |
For example, `180` degrees returns approximately `-1`, as does `π` radians.
Small floating-point differences are normal.
# Divide
Source: https://learn.workflow.dog/reference/actions/math/divide
Divide two numbers with decimal or integer division.
The **Divide** action divides a dividend by a nonzero divisor. It can return a
decimal quotient or a whole-number quotient with a remainder.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | ------- | -------- | -------------------------------------------------------------- |
| **Dividend** | Number | Yes | The value being divided. |
| **Divisor** | Number | Yes | The nonzero value to divide by. |
| **Use Integer Division?** | Boolean | No | Returns a floored quotient and remainder. Defaults to `false`. |
## Outputs
| Output | Type | When shown | Description |
| ------------- | ------ | ---------------------- | -------------------------------- |
| **Quotient** | Number | Always | The result of the division. |
| **Remainder** | Number | Integer division is on | The remainder from the division. |
With **Dividend** set to `17` and **Divisor** set to `5`, **Quotient** is
`3.4`.
With the same inputs, **Quotient** is `3` and **Remainder** is `2`.
The quotient is rounded down with `floor`, so negative inputs can differ
from truncation toward zero. For example, `-17 ÷ 5` produces a quotient of
`-4` and a remainder of `-2`.
Division by zero is rejected before the calculation runs.
# E
Source: https://learn.workflow.dog/reference/actions/math/e
Return Euler's number, the base of natural logarithms.
The **E** action provides Euler's number for exponential growth, decay, and
natural-logarithm calculations.
## Outputs
| Output | Type | Description |
| ------ | ------ | --------------------------------------------------------------------------------- |
| **E** | Number | Euler's number at JavaScript number precision, approximately `2.718281828459045`. |
Connect **E** to **Power** as the base to calculate `e^x`.
# Floor
Source: https://learn.workflow.dog/reference/actions/math/floor
Round a number downward to the nearest integer.
The **Floor** action returns the largest integer less than or equal to the
input.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ------------------- |
| **Number** | Number | Yes | The value to round. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------------- |
| **Floored** | Number | The input rounded toward negative infinity. |
For example, `4.99` becomes `4`, while `-4.01` becomes `-5`.
# Greater Than
Source: https://learn.workflow.dog/reference/actions/math/greater-than
Check whether one number is larger than another.
The **Greater Than** action compares two numbers using `A > B`.
## Inputs
| Input | Type | Required | Description |
| ----- | ------ | -------- | ---------------------------- |
| **A** | Number | Yes | The value on the left side. |
| **B** | Number | Yes | The value on the right side. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ---------------------------------------- |
| **Result** | Boolean | `true` when **A** is greater than **B**. |
Equal values return `false`.
# Greater Than or Equal
Source: https://learn.workflow.dog/reference/actions/math/greater-than-or-equal
Check whether one number is at least another.
The **Greater Than or Equal** action compares two numbers using `A ≥ B`.
## Inputs
| Input | Type | Required | Description |
| ----- | ------ | -------- | ---------------------------- |
| **A** | Number | Yes | The value on the left side. |
| **B** | Number | Yes | The value on the right side. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ---------------------------------------------------- |
| **Result** | Boolean | `true` when **A** is greater than or equal to **B**. |
For example, `10 ≥ 10` and `12 ≥ 10` both return `true`.
# Number in Range
Source: https://learn.workflow.dog/reference/actions/math/in-range
Check whether a number falls inside inclusive bounds.
The **Number in Range** action returns whether a value is between a minimum and
maximum, including both boundaries.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ----------------------------- |
| **Number** | Number | Yes | The value to test. |
| **Min** | Number | Yes | The inclusive lower boundary. |
| **Max** | Number | Yes | The inclusive upper boundary. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ---------------------------------------------------- |
| **Result** | Boolean | `true` when `Min ≤ Number ≤ Max`; otherwise `false`. |
For a range of `0` through `100`, the values `0`, `50`, and `100` all return
`true`.
Supply the lower boundary as **Min** and the upper boundary as **Max**.
Reversed bounds do not get reordered and cannot match a normal finite number.
# Inverse
Source: https://learn.workflow.dog/reference/actions/math/inverse
Calculate the reciprocal of a nonzero number.
The **Inverse** action divides `1` by the input value.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ---------------------------- |
| **Number** | Number | Yes | The nonzero value to invert. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------ |
| **Inverse** | Number | The reciprocal, calculated as `1/x`. |
For example, `4` produces `0.25`, and `-2` produces `-0.5`.
An input of `0` is rejected because its reciprocal is undefined.
# Less Than
Source: https://learn.workflow.dog/reference/actions/math/less-than
Check whether one number is smaller than another.
The **Less Than** action compares two numbers using `A < B`.
## Inputs
| Input | Type | Required | Description |
| ----- | ------ | -------- | ---------------------------- |
| **A** | Number | Yes | The value on the left side. |
| **B** | Number | Yes | The value on the right side. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------- |
| **Result** | Boolean | `true` when **A** is less than **B**. |
Equal values return `false`.
# Less Than or Equal
Source: https://learn.workflow.dog/reference/actions/math/less-than-or-equal
Check whether one number is no larger than another.
The **Less Than or Equal** action compares two numbers using `A ≤ B`.
## Inputs
| Input | Type | Required | Description |
| ----- | ------ | -------- | ---------------------------- |
| **A** | Number | Yes | The value on the left side. |
| **B** | Number | Yes | The value on the right side. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------- |
| **Result** | Boolean | `true` when **A** is less than or equal to **B**. |
For example, `10 ≤ 10` and `8 ≤ 10` both return `true`.
# Logarithm
Source: https://learn.workflow.dog/reference/actions/math/log
Calculate a natural logarithm or a logarithm in a chosen base.
The **Logarithm** action calculates the exponent to which a base must be raised
to produce the input number. Leave **Base** empty for the natural logarithm.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | --------------------------------------------------- |
| **Number** | Number | Yes | A non-negative value whose logarithm is calculated. |
| **Base** | Number | No | The logarithm base. Defaults to `e`. |
## Outputs
| Output | Type | Description |
| ------- | ------ | ----------------------------------- |
| **Log** | Number | The logarithm in the selected base. |
For example, **Number** `1000` with **Base** `10` returns approximately `3`.
Although zero is accepted, its logarithm is negative infinity. Bases `1`, `0`,
and negative values can produce infinity or `NaN`; use a positive base other
than `1` for ordinary real-number logarithms.
# Map Range
Source: https://learn.workflow.dog/reference/actions/math/map-range
Convert a number's position in one range to another range.
The **Map Range** action linearly maps a value from an input range to the
corresponding position in an output range. Use it for percentages, scores,
coordinates, and unit-like scaling.
## Inputs
| Input | Type | Required | Description |
| ----------------- | ------- | -------- | --------------------------------------------------------------- |
| **Number** | Number | Yes | The value to map. |
| **In Min** | Number | Yes | The start of the input range. |
| **In Max** | Number | Yes | The end of the input range. |
| **Out Min** | Number | Yes | The corresponding start of the output range. |
| **Out Max** | Number | Yes | The corresponding end of the output range. |
| **Clamp Result?** | Boolean | No | Keeps the result within the output bounds. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | --------------------------------------- |
| **Result** | Number | The value mapped into the output range. |
## Example
Map a five-star rating into a percentage:
| Setting | Value |
| ----------- | ----- |
| **Number** | `4` |
| **In Min** | `1` |
| **In Max** | `5` |
| **Out Min** | `0` |
| **Out Max** | `100` |
The result is `75`.
When clamping is off, values outside the input range are extrapolated. In the
example above, a rating of `6` maps to `125`. Turn on **Clamp Result?** to return
`100` instead.
Reversed output ranges are supported. Clamping uses the lower and upper
numeric output bounds regardless of their direction.
**In Min** and **In Max** must be different. Equal input bounds cause a
division by zero and produce a non-finite result.
# Max
Source: https://learn.workflow.dog/reference/actions/math/max
Return the largest value from two or more numbers.
The **Max** action examines a repeatable list and returns its largest number.
## Inputs
| Input | Type | Required | Description |
| ----------- | --------------- | -------- | ------------------------------- |
| **Numbers** | List of numbers | Yes | At least two values to compare. |
## Outputs
| Output | Type | Description |
| ------- | ------ | ---------------------------- |
| **Max** | Number | The largest supplied number. |
For example, `8`, `-3`, and `4.5` produce `8`.
Zero and empty repeat slots are currently ignored by this action. If zero
needs to participate in the comparison, compare it explicitly with the
returned value in a later step.
# Min
Source: https://learn.workflow.dog/reference/actions/math/min
Return the smallest value from two or more numbers.
The **Min** action examines a repeatable list and returns its smallest number.
## Inputs
| Input | Type | Required | Description |
| ----------- | --------------- | -------- | ------------------------------- |
| **Numbers** | List of numbers | Yes | At least two values to compare. |
## Outputs
| Output | Type | Description |
| ------- | ------ | ----------------------------- |
| **Min** | Number | The smallest supplied number. |
For example, `8`, `-3`, and `4.5` produce `-3`.
Zero and empty repeat slots are currently ignored by this action. If zero
needs to participate in the comparison, compare it explicitly with the
returned value in a later step.
# Multiply
Source: https://learn.workflow.dog/reference/actions/math/multiply
Multiply two or more numbers together.
The **Multiply** action multiplies a repeatable list of numbers.
## Inputs
| Input | Type | Required | Description |
| ----------- | --------------- | -------- | --------------------------------- |
| **Numbers** | List of numbers | Yes | At least two factors to multiply. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------ |
| **Product** | Number | The product of all supplied numbers. |
Empty repeat slots are treated as `1`. For example, `4`, `2.5`, and `-3`
produce `-30`.
# Negate
Source: https://learn.workflow.dog/reference/actions/math/negate
Reverse the sign of a number.
The **Negate** action multiplies a number by `-1`. Positive values become
negative, and negative values become positive.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | -------------------- |
| **Number** | Number | Yes | The value to negate. |
## Outputs
| Output | Type | Description |
| ------------ | ------ | --------------------------------- |
| **Negation** | Number | The input with its sign reversed. |
For example, `8` produces `-8`, while `-2.5` produces `2.5`.
# Pi
Source: https://learn.workflow.dog/reference/actions/math/pi
Return the mathematical constant π.
The **Pi** action provides the numeric constant π for calculations involving
circles, angles, and periodic formulas.
## Outputs
| Output | Type | Description |
| ------ | ------ | -------------------------------------------------------------------- |
| **Pi** | Number | π at JavaScript number precision, approximately `3.141592653589793`. |
For example, multiply **Pi** by a circle's diameter to calculate its
circumference.
# Power
Source: https://learn.workflow.dog/reference/actions/math/power
Raise a base number to an exponent.
The **Power** action calculates `base` raised to `exponent`.
## Inputs
| Input | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------ |
| **Base** | Number | Yes | The number being raised. |
| **Exponent** | Number | Yes | The power applied to the base. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ----------------------------- |
| **Result** | Number | The value of `base^exponent`. |
Examples include `2^8 = 256`, `9^0.5 = 3`, and `10^-2 = 0.01`.
Some combinations do not have a real-number result. For example, a negative
base with a fractional exponent can produce `NaN`.
# Random Number
Source: https://learn.workflow.dog/reference/actions/math/random
Generate a random decimal or whole number within a range.
The **Random Number** action first generates a pseudorandom decimal from
**Min** inclusive up to **Max** exclusive. Whole-number mode floors that value.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------- | -------- | ------------------------------------------------ |
| **Min** | Number | Yes | The inclusive lower end of the range. |
| **Max** | Number | Yes | The exclusive upper end of the range. |
| **Only Whole Numbers?** | Boolean | No | Floors the generated value. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ------------------------------------- |
| **Random** | Number | A newly generated value in the range. |
With integer boundaries **Min** `1`, **Max** `7`, and whole numbers enabled,
the possible outputs are `1` through `6`.
This action uses general-purpose pseudorandom selection. It is not suitable
for security-sensitive tokens, secrets, or cryptographic use.
Whole-number mode uses floor rather than choosing integers from adjusted
bounds. A fractional minimum can therefore produce a whole number below that
minimum; for example, values starting at `1.5` can floor to `1`.
Use **Min** less than **Max**. Reversing the range changes the arithmetic and,
with whole numbers enabled, can produce values outside the intuitive bounds.
# Round
Source: https://learn.workflow.dog/reference/actions/math/round
Round a number to a chosen number of decimal places.
The **Round** action rounds a number to the nearest value at the configured
decimal precision.
## Inputs
| Input | Type | Required | Description |
| ------------------ | ------ | -------- | ----------------------------------------------------- |
| **Number** | Number | Yes | The value to round. |
| **Decimal Places** | Number | No | Non-negative whole-number precision. Defaults to `0`. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | -------------------------- |
| **Rounded** | Number | The rounded numeric value. |
## Examples
| Number | Decimal Places | Rounded |
| --------- | -------------- | ----------------------------------------------- |
| `12.3456` | `0` | `12` |
| `12.3456` | `2` | `12.35` |
| `1.005` | `2` | May be `1` due to floating-point representation |
The result is a number, so trailing zeroes are not preserved. Rounding `4.5`
to two decimal places returns the numeric value `4.5`, not formatted text
`4.50`.
# Sine
Source: https://learn.workflow.dog/reference/actions/math/sin
Calculate the sine of an angle in radians or degrees.
The **Sine** action calculates the sine of an angle.
## Inputs
| Input | Type | Required | Description |
| -------------- | ------------------ | -------- | ------------------------------------------------ |
| **Angle** | Number | Yes | The angle to evaluate. |
| **Angle Unit** | Radians or Degrees | Yes | How to interpret **Angle**. Defaults to radians. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ---------------------------- |
| **Result** | Number | The sine of the input angle. |
For example, `90` degrees returns approximately `1`, as does `π / 2` radians.
Small floating-point differences are normal.
# Square Root
Source: https://learn.workflow.dog/reference/actions/math/sqrt
Calculate the principal square root of a number.
The **Square Root** action returns the non-negative value that, when multiplied
by itself, equals the input.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | -------------------------------------- |
| **Number** | Number | Yes | A number greater than or equal to `0`. |
## Outputs
| Output | Type | Description |
| -------- | ------ | --------------------------------------- |
| **Sqrt** | Number | The principal square root of the input. |
For example, `81` produces `9`.
Negative inputs are rejected.
# Subtract
Source: https://learn.workflow.dog/reference/actions/math/subtract
Subtract each later number from the first.
The **Subtract** action starts with the first number, then subtracts every
remaining number from it in order.
## Inputs
| Input | Type | Required | Description |
| ----------- | --------------- | -------- | ------------------------------------------ |
| **Numbers** | List of numbers | Yes | At least two values, in calculation order. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | ---------------------------------- |
| **Difference** | Number | The result after all subtractions. |
For example, `20`, `3`, and `2` are evaluated as `20 - 3 - 2`, producing `15`.
Empty repeat slots are treated as `0`.
# Tangent
Source: https://learn.workflow.dog/reference/actions/math/tan
Calculate the tangent of an angle in radians or degrees.
The **Tangent** action calculates the tangent of an angle.
## Inputs
| Input | Type | Required | Description |
| -------------- | ------------------ | -------- | ------------------------------------------------ |
| **Angle** | Number | Yes | The angle to evaluate. |
| **Angle Unit** | Radians or Degrees | Yes | How to interpret **Angle**. Defaults to radians. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ------------------------------- |
| **Result** | Number | The tangent of the input angle. |
For example, `45` degrees returns approximately `1`.
Tangent is undefined at angles such as `90°` and `π / 2`. Floating-point
arithmetic may return a very large finite value near those angles instead of
an explicit error.
# Verify Email
Source: https://learn.workflow.dog/reference/actions/millionverifier/verify-email
Check an email address with MillionVerifier.
**Verify Email** sends one syntactically valid email address to
MillionVerifier and returns its deliverability quality.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ----------------------- | -------- | ---------------------------------- |
| **Third-party account** | MillionVerifier account | Yes | The API key used for verification. |
| **Email** | String | Yes | The address to verify. |
## Output
| Output | Type | Description |
| ----------- | ------ | ------------------------------------------------------------- |
| **Quality** | String | `good`, `bad`, or `risky` when the service provides a result. |
The output is empty when MillionVerifier returns an empty or missing quality.
Treat `risky` as a separate branch instead of silently accepting or rejecting
it. The right policy depends on whether you are validating signups, cleaning a
list, or protecting a transactional send.
# Create Object
Source: https://learn.workflow.dog/reference/actions/objects/build
Build an object from a repeatable list of keys and values.
The **Create Object** action assembles key/value entries into a new object. Add
one property input for every field the workflow should expose together.
## Inputs
| Input | Type | Required | Description |
| -------------- | ----------------- | --------- | ------------------------------------------ |
| **Properties** | Key/value entries | No | The fields included in the new object. |
| **Key** | String | Per entry | The property name. |
| **Value** | Any | Per entry | The value stored under that property name. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ------------------------------------------- |
| **Object** | Object | The object built from all property entries. |
## Example
Add these entries:
| Key | Value |
| -------- | ------ |
| `name` | `Ada` |
| `active` | `true` |
| `score` | `98` |
The output is:
```json theme={null}
{
"name": "Ada",
"active": true,
"score": 98
}
```
Property values keep their original types. A connected number remains a
number; it is not converted to text.
# Are Objects Equal?
Source: https://learn.workflow.dog/reference/actions/objects/compare-objects
Deeply compare two objects for equivalent contents.
The **Are Objects Equal?** action performs a deep equality comparison. It checks
nested objects and arrays, not just whether the two inputs are the same
reference.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ----------------------------- |
| **First** | Object | Yes | The first object to compare. |
| **Second** | Object | Yes | The second object to compare. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ----------------------------------------- |
| **Result** | Boolean | `true` when the objects are deeply equal. |
Object property order does not affect equality, but array order does. These
objects are equal:
```json theme={null}
{ "name": "Ada", "tags": ["admin", "beta"] }
{ "tags": ["admin", "beta"], "name": "Ada" }
```
Changing the second array to `["beta", "admin"]` makes the result `false`.
# Count Properties
Source: https://learn.workflow.dog/reference/actions/objects/count-properties
Count an object's top-level properties.
The **Count Properties** action returns the number of enumerable top-level keys
in an object.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ---------------------------------- |
| **Object** | Object | Yes | The object whose keys are counted. |
## Outputs
| Output | Type | Description |
| --------- | ------ | ----------------------------------- |
| **Count** | Number | The number of top-level properties. |
Nested fields are not counted separately. For
`{"name":"Ada","address":{"city":"London"}}`, the count is `2`.
# Delete Properties
Source: https://learn.workflow.dog/reference/actions/objects/delete-properties
Return a copy of an object without selected properties.
The **Delete Properties** action removes a repeatable list of property paths
from an object. The original input is not returned as the output.
## Inputs
| Input | Type | Required | Description |
| -------------- | --------------- | -------- | ------------------------------------------ |
| **Object** | Object | Yes | The object to copy and remove fields from. |
| **Properties** | List of strings | No | Top-level keys or nested paths to remove. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | ------------------------------------------- |
| **New Object** | Object | The object without the selected properties. |
Given:
```json theme={null}
{
"id": 1042,
"customer": { "name": "Ada", "email": "ada@example.com" }
}
```
Removing `customer.email` preserves the rest of `customer`. Missing paths are
ignored.
Use **Pick Properties** when the fields to keep are easier to list than the
fields to remove.
# Empty Object
Source: https://learn.workflow.dog/reference/actions/objects/empty-object
Provide a new object with no properties.
The **Empty Object** action returns `{}`. Use it as a starting value for **Set
Properties**, a default object for a branch, or an explicit empty payload.
## Outputs
| Output | Type | Description |
| ---------- | ------ | -------------------------------- |
| **Object** | Object | A new object with no properties. |
# Find Matching Object
Source: https://learn.workflow.dog/reference/actions/objects/find-matching-object
Find the first or all objects whose property meets a condition.
The **Find Matching Object** action searches a list using one property path and
a configurable comparison. Return the first match for lookup workflows, or all
matches for filtering workflows.
## Inputs
| Input | Type | Required | Description |
| -------------------------- | --------------- | --------- | ------------------------------------------------------------------- |
| **Objects** | List of objects | Yes | The objects to search, in priority order. |
| **Property Name** | String | Yes | The top-level key or nested path whose value is tested. |
| **Match Mode** | Match mode | Yes | The comparison to perform. Defaults to **Exact Value**. |
| **Search Value** | Varies | Sometimes | Required by value, text, regex, and numeric modes. |
| **Find Multiple Objects?** | Boolean | No | Returns every match instead of only the first. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------------- | ------ | ----------------------------------------- |
| **Found Object** | Object | The first matching object in input order. |
When nothing matches, no object value is found.
| Output | Type | Description |
| ----------------- | --------------- | ------------------------------------- |
| **Found Objects** | List of objects | Every matching object in input order. |
When nothing matches, the output is an empty list.
## Match modes
| Mode | Search Value | A property matches when… |
| ------------------------- | ------------------ | ------------------------------------------------------ |
| **Exact Value** | Any | It is loosely equal to the search value. |
| **Empty** | None | It is exactly an empty string. |
| **Not Empty** | None | It is anything other than an empty string. |
| **Contains Text** | String | Its text form contains the search text, ignoring case. |
| **Matches Regex** | Regular expression | Its text form matches the pattern. |
| **Greater Than** | Number | It is a number greater than the search value. |
| **Less Than** | Number | It is a number less than the search value. |
| **Greater Than or Equal** | Number | It is a number at least as large as the search value. |
| **Less Than or Equal** | Number | It is a number no larger than the search value. |
| **Is True** | None | It is the boolean `true`. |
| **Is False** | None | It is the boolean `false`. |
| **Is Truthy** | None | JavaScript treats it as truthy. |
| **Is Falsy** | None | JavaScript treats it as falsy. |
**Property Name** supports paths such as `customer.plan` and
`items[0].quantity`.
### Important comparison details
* **Exact Value** uses loose primitive equality, so the number `42` can match
the text `"42"`, and `null` can match a missing value.
* **Empty** matches only empty text. It does not match `null`, missing
properties, empty objects, or empty lists.
* Consequently, **Not Empty** also matches missing properties and non-string
values.
* **Contains Text** converts objects and lists to JSON text and compares
without case sensitivity.
* Numeric modes require the property itself to be a number.
* Falsy values include `false`, `0`, empty text, `null`, and missing values.
For **Matches Regex**, turn off the regex's **Global** flag. Reusing a global
regex across several objects can advance its internal match position and skip
otherwise valid matches.
# Get Keys as List
Source: https://learn.workflow.dog/reference/actions/objects/get-keys
Return an object's top-level property names in a list.
The **Get Keys as List** action returns all enumerable top-level keys from an
object in their normal object iteration order.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ---------------------- |
| **Object** | Object | Yes | The object to inspect. |
## Outputs
| Output | Type | Description |
| -------- | --------------- | -------------------------------------- |
| **Keys** | List of strings | The object's top-level property names. |
For `{"name":"Ada","active":true}`, the output is `["name", "active"]`.
Nested keys are not flattened.
# Get Properties
Source: https://learn.workflow.dog/reference/actions/objects/get-properties
Expose selected values from one object as separate outputs.
The **Get Properties** action reads a repeatable list of property paths from one
object. Every property input creates a corresponding output, which makes
specific fields easy to connect without passing the entire object downstream.
## Inputs
| Input | Type | Required | Description |
| -------------- | --------------- | -------- | ----------------------------------- |
| **Object** | Object | Yes | The object to read. |
| **Properties** | List of strings | No | The keys or nested paths to expose. |
## Outputs
The node adds one output for every **Properties** entry:
| Output | Type | Description |
| ------------------- | ---- | ---------------------------------------- |
| **Value for "key"** | Any | The value found at that property's path. |
If an entry is not yet configured, its output is labeled **Value for Key 1**,
**Value for Key 2**, and so on.
## Nested paths
Dot and bracket notation can read nested values. Given:
```json theme={null}
{
"customer": {
"name": "Ada",
"addresses": [{ "city": "Boston" }]
}
}
```
Add `customer.name` and `customer.addresses[0].city` to expose `Ada` and
`Boston` as two outputs.
If a path does not exist, its output has an undefined value. The action does
not fail and does not substitute `null`.
# Get Properties From Each
Source: https://learn.workflow.dog/reference/actions/objects/get-properties-for-each
Collect selected property values across a list of objects.
The **Get Properties From Each** action reads the same property paths from every
object in a list. Each requested property becomes an output list aligned with
the input objects.
## Inputs
| Input | Type | Required | Description |
| -------------- | --------------- | -------- | ------------------------------------- |
| **Objects** | List of objects | No | The objects to read, in output order. |
| **Properties** | List of strings | No | The keys to collect from each object. |
## Outputs
Every property entry creates a list output:
| Output | Type | Description |
| -------------------- | ----------- | --------------------------------------------- |
| **Values for "key"** | List of any | That property's value from each input object. |
For:
```json theme={null}
[
{ "name": "Ada", "score": 98 },
{ "name": "Grace", "score": 95 }
]
```
Requesting `name` and `score` creates outputs equivalent to:
```json theme={null}
["Ada", "Grace"]
[98, 95]
```
The output lists preserve input order and have one position per object. A
missing property contributes an undefined value at that position.
Dot and bracket paths such as `customer.name` or `items[0].sku` can collect
nested values.
# Get Values as List
Source: https://learn.workflow.dog/reference/actions/objects/get-values
Return an object's top-level values in a list.
The **Get Values as List** action returns the values of an object's enumerable
top-level properties. Their order corresponds to **Get Keys as List** for the
same object.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ---------------------- |
| **Object** | Object | Yes | The object to inspect. |
## Outputs
| Output | Type | Description |
| ---------- | ----------- | ------------------------------ |
| **Values** | List of any | The object's top-level values. |
For `{"name":"Ada","active":true}`, the output is `["Ada", true]`. Nested
objects remain individual values.
# Has Key?
Source: https://learn.workflow.dog/reference/actions/objects/has-key
Check whether an object contains a property or nested path.
The **Has Key?** action checks whether a property path exists in an object. It
returns `true` even when the property's value is `null`, `false`, or empty
text.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | ---------------------------------------- |
| **Object** | Object | Yes | The object to inspect. |
| **Key** | String | Yes | A top-level key or nested property path. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ----------------------------------------------- |
| **Result** | Boolean | `true` when the path exists; otherwise `false`. |
Dot and bracket paths are supported. Given:
```json theme={null}
{
"customer": {
"addresses": [{ "city": "Boston" }]
}
}
```
Both `customer.addresses` and `customer.addresses[0].city` return `true`.
This checks existence, not whether the value is useful or non-empty. A key
whose value is `undefined` can still be treated differently by later actions.
# Is Empty?
Source: https://learn.workflow.dog/reference/actions/objects/is-empty
Check whether an object has no top-level properties.
The **Is Empty?** action returns `true` when an object has zero enumerable
top-level keys.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | -------------------- |
| **Object** | Object | Yes | The object to check. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------------ |
| **Result** | Boolean | `true` when the object has no keys; otherwise `false`. |
`{}` is empty. `{"value": null}` is not empty because it still has the `value`
property.
# Is Object?
Source: https://learn.workflow.dog/reference/actions/objects/is-object
Check whether a value has JavaScript's non-null object type.
The **Is Object?** action checks the runtime type of any workflow value.
## Inputs
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------------ |
| **Result** | Boolean | `true` for a non-null object value; otherwise `false`. |
Plain objects and arrays return `true`. Text, numbers, booleans, and `null`
return `false`.
This is a broad runtime check. It does not guarantee that the value is a plain
key/value object; lists also count as objects.
# Map Keys
Source: https://learn.workflow.dog/reference/actions/objects/map-keys
Rename or move property paths within an object.
The **Map Keys** action copies an object, then applies a repeatable set of
old-path to new-path mappings. Each mapping moves the value to its new location
and removes the old path.
## Inputs
| Input | Type | Required | Description |
| ---------------- | --------------- | --------- | ----------------------------------------- |
| **Object** | Object | Yes | The object whose paths will be changed. |
| **Key Mappings** | Mapping entries | No | Old and new path pairs, applied in order. |
| **Old Key** | String | Per entry | The existing key or nested path. |
| **New Key** | String | Per entry | The destination key or nested path. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | -------------------------------------- |
| **Result** | Object | A copied object with mappings applied. |
## Rename and restructure
Given:
```json theme={null}
{
"first_name": "Ada",
"contact": { "email": "ada@example.com" }
}
```
Map `first_name` to `name` and `contact.email` to `customer.email`:
```json theme={null}
{
"name": "Ada",
"contact": {},
"customer": { "email": "ada@example.com" }
}
```
Dot and bracket notation are supported for both paths. A missing old path is
skipped.
Mappings run in order and can overwrite an existing destination. A later
mapping also sees the changes made by earlier mappings, so avoid chains and
overlapping paths unless that sequence is intentional.
# Map Keys For Each
Source: https://learn.workflow.dog/reference/actions/objects/map-keys-for-each
Apply the same key-path mappings to every object in a list.
The **Map Keys For Each** action renames or moves paths in every object in a
list. It preserves list order and returns newly copied objects.
## Inputs
| Input | Type | Required | Description |
| ---------------- | --------------- | --------- | -------------------------------------------- |
| **Array** | List of objects | Yes | The objects to transform. |
| **Key Mappings** | Mapping entries | No | Old and new path pairs applied to each item. |
| **Old Key** | String | Per entry | The existing key or nested path. |
| **New Key** | String | Per entry | The destination key or nested path. |
## Outputs
| Output | Type | Description |
| ---------- | --------------- | ------------------------------------------------ |
| **Result** | List of objects | The transformed objects in their original order. |
## Example
Map `first_name` to `name` for:
```json theme={null}
[
{ "first_name": "Ada", "id": 1 },
{ "first_name": "Grace", "id": 2 }
]
```
The result is:
```json theme={null}
[
{ "name": "Ada", "id": 1 },
{ "name": "Grace", "id": 2 }
]
```
Nested paths are supported, and missing old paths are skipped for only the
objects that lack them.
Mappings run in order on each object. Existing destination values can be
overwritten, and overlapping mappings can affect one another.
# Merge Objects
Source: https://learn.workflow.dog/reference/actions/objects/merge-objects
Combine objects in order with optional deep merging.
The **Merge Objects** action combines a repeatable list of objects. When the
same property appears more than once, the value from the later object takes
precedence.
## Inputs
| Input | Type | Required | Description |
| -------------- | --------------- | -------- | -------------------------------------------------------------------- |
| **Objects** | List of objects | No | The objects to combine, in precedence order. |
| **Deep Merge** | Boolean | No | Merges nested values instead of replacing them. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ----------------- | ------ | -------------------- |
| **Merged Object** | Object | The combined object. |
## Shallow and deep merging
Nested objects are treated as complete values. Merging:
```json theme={null}
{ "customer": { "name": "Ada", "plan": "pro" } }
{ "customer": { "active": true } }
```
returns:
```json theme={null}
{ "customer": { "active": true } }
```
Turn on **Deep Merge** to combine nested properties:
```json theme={null}
{
"customer": {
"name": "Ada",
"plan": "pro",
"active": true
}
}
```
Deep merging arrays combines them by index rather than simply appending or
replacing the complete list. If array behavior matters, shape those values
before merging.
# Object
Source: https://learn.workflow.dog/reference/actions/objects/object
Build and merge one or more property sets into a final object.
The **Object** action is a flexible object builder. Each repeatable input can be
connected as an object or configured as its own set of key/value properties.
All inputs are then combined in order.
## Inputs
| Input | Type | Required | Description |
| ----------------- | --------------- | --------- | ------------------------------------------------------- |
| **Input Objects** | List of objects | No | Objects or configured property sets to combine. |
| **Key** | String | Per entry | A property name or nested property path. |
| **Value** | Any | Per entry | The value assigned to the key. |
| **Deep Merge** | Boolean | No | Merges overlapping nested objects. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------------- | ------ | ------------------------------------- |
| **Final Object** | Object | The completed object from all inputs. |
## Build with property paths
Property keys are expanded as paths before the objects are merged. Configure:
| Key | Value |
| --------------- | ----- |
| `customer.name` | `Ada` |
| `customer.plan` | `pro` |
To create:
```json theme={null}
{
"customer": {
"name": "Ada",
"plan": "pro"
}
}
```
## Merge precedence
Later input objects override earlier ones. With **Deep Merge** off, an
overlapping nested object is replaced as a whole. Turn it on to preserve
non-conflicting nested properties.
Deep merging arrays combines values by index. Use dedicated list actions when
you need append, concatenate, or replacement semantics.
# Pick Properties
Source: https://learn.workflow.dog/reference/actions/objects/pick-properties
Return a new object containing only selected property paths.
The **Pick Properties** action creates an object from a repeatable list of
properties selected from the input. It is useful for shaping payloads and
removing fields that should not leave the workflow.
## Inputs
| Input | Type | Required | Description |
| -------------- | --------------- | -------- | ----------------------------------------- |
| **Object** | Object | Yes | The source object. |
| **Properties** | List of strings | No | Top-level keys or nested paths to retain. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | -------------------------------------------- |
| **New Object** | Object | A new object containing the selected values. |
Given:
```json theme={null}
{
"id": 1042,
"customer": { "name": "Ada", "email": "ada@example.com" }
}
```
Picking `id` and `customer.email` returns:
```json theme={null}
{
"id": 1042,
"customer": { "email": "ada@example.com" }
}
```
Missing paths are ignored. An empty property list returns an empty object.
# Set Properties
Source: https://learn.workflow.dog/reference/actions/objects/set-properties
Add or replace properties on a copy of an object.
The **Set Properties** action copies an optional source object, then applies a
repeatable list of key/value entries. Use it to enrich an object without
discarding its existing fields.
## Inputs
| Input | Type | Required | Description |
| ------------------- | ----------------- | --------- | ------------------------------------------------ |
| **Original Object** | Object | No | The object to copy. Defaults to an empty object. |
| **Properties** | Key/value entries | No | Fields to add or replace. |
| **Key** | String | Per entry | A top-level key or nested property path. |
| **Value** | Any | Per entry | The value assigned at that path. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | ------------------------------------------- |
| **New Object** | Object | The copied object with all entries applied. |
## Example
Starting with:
```json theme={null}
{
"id": 1042,
"customer": { "name": "Ada" }
}
```
Set `customer.active` to `true` and `status` to `ready`:
```json theme={null}
{
"id": 1042,
"customer": { "name": "Ada", "active": true },
"status": "ready"
}
```
Dot and bracket paths create nested objects or arrays when needed. Later
entries can overwrite values set by earlier entries.
The source object is cloned before changes are applied, so the output can be
modified without intentionally mutating the connected input value.
# Transform Properties
Source: https://learn.workflow.dog/reference/actions/objects/transform-properties
Run another workflow once for each property in an object.
The **Transform Properties** action applies a selected workflow to every
top-level property of an object. It preserves each original key and replaces
its value with the selected workflow's output data.
This is a sub-workflow action. The selected workflow runs separately for each
property and must use a **Sub-Workflow** trigger. Use **Return Data** in that
workflow to provide the transformed value.
## Inputs
| Input | Type | Required | Description |
| --------------------- | -------- | -------- | ------------------------------------------------------ |
| **Selected Workflow** | Workflow | Yes | The workflow used to transform each property. |
| **Object** | Object | Yes | The object whose top-level properties are transformed. |
## Outputs
| Output | Type | Description |
| ---------------------- | ------ | ------------------------------------------------- |
| **Transformed Object** | Object | The original keys mapped to sub-workflow outputs. |
## Configure the selected workflow
For each property, the selected workflow's **Data In** contains:
```json theme={null}
{
"key": "propertyName",
"value": "original property value"
}
```
Use `value` for the transformation and `key` when the logic depends on which
property is being processed. Connect the transformed value to **Return Data**.
That returned data becomes the new value under the original key.
For example, if the input is:
```json theme={null}
{
"firstName": " Ada ",
"lastName": " LOVELACE "
}
```
A selected workflow that trims and lowercases its `value`, then returns that
string, produces:
```json theme={null}
{
"firstName": "ada",
"lastName": "lovelace"
}
```
## Execution behavior
* Only top-level properties are iterated.
* Properties are processed one at a time in object-entry order.
* If the selected workflow returns no output data, that property's new value is
`null`.
* If any sub-workflow run fails, **Transform Properties** fails rather than
returning a partial object.
* Normal workflow recursion-depth limits still apply.
**Return Data** can return a primitive, list, or object. Design that returned
value as the exact replacement each original property should receive.
# Yes/No Question
Source: https://learn.workflow.dog/reference/actions/openai/binary-decision
Ask an OpenAI model for a boolean decision.
**Yes/No Question** turns a natural-language question and optional context into
a strict boolean. Use it when a workflow needs an AI judgment that can connect
directly to conditional logic.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------------- |
| **Third-party account** | OpenAI account | Yes | The API key used for the request. |
| **Model** | OpenAI model | Yes | Defaults to GPT-5 Mini. |
| **Question** | String | Yes | A question that can be answered yes or no. |
| **Additional Text** | String | No | The content or facts the model should judge. |
## Output
| Output | Type | Description |
| ------------ | ------- | ---------------------------------- |
| **Decision** | Boolean | `true` for yes and `false` for no. |
## Example: decide whether a message needs escalation
* **Question** — `Does this customer message describe an urgent safety risk?`
* **Additional Text** — Connect the incoming message.
Route **Decision** into an **If**-style branch: `true` can alert an on-call
person, while `false` continues normal processing.
Make the decision criteria explicit. “Is this important?” is ambiguous; “Does
this mention account takeover, exposed credentials, or unauthorized access?”
gives the model a usable rule.
# Chat
Source: https://learn.workflow.dog/reference/actions/openai/chat
Send a prompt, files, and optional instructions to an OpenAI model.
The **Chat** action sends a single prompt to an OpenAI model. Use it for
free-form text generation, questions about images or PDFs, web-assisted
research, and responses that must match a JSON schema.
Chat is stateless: each run sends the current prompt, system prompt, and
files. It does not remember earlier workflow runs or previous Chat actions.
## Quick start
Add an OpenAI account when the node asks for a **Third-party account**. The
account must contain a valid OpenAI API key.
Connect a string to **Prompt**, or set a fixed value on the node. Include all
of the context the model needs for this run.
**GPT-5.1** is selected by default. Standard models expose web search and
temperature controls; reasoning models expose reasoning effort instead.
Connect **Response** to the next action. If you enable structured output,
connect properties from **Structured Response** instead.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | --------- | -------------------------------------------------------------------------------------------------- |
| **Third-party account** | OpenAI account | Yes | The OpenAI API key used to make the request. |
| **Prompt** | String | Yes | The user message sent to the model. |
| **Model** | Model | Yes | The model that handles the request. Defaults to **GPT-5.1**. |
| **System Prompt** | String | No | Instructions that define the model's role, constraints, or response style. |
| **Files** | List of files | No | Images or PDFs sent with the prompt. Add more file inputs when the model needs multiple documents. |
| **Structured Output** | Boolean | No | Replaces the text response with an object that follows a JSON schema. Defaults to off. |
| **JSON Schema** | String | Sometimes | Required when **Structured Output** is enabled. The schema's outer type must be `object`. |
### Model controls
Standard models support:
* **Web Search** — Lets the model search the web before answering. Defaults
to off.
* **Temperature** — Controls how varied the response can be, from `0`
(more focused) to `2` (more varied). Defaults to `1`.
Available models:
* GPT-5.1
* GPT-5 Nano
* GPT-5 Mini
* GPT-5
* GPT-4.1 Mini
* GPT-4.1
* GPT-4o Mini
* GPT-4o
Reasoning models replace web search and temperature with
**Reasoning Effort**:
* `low` — Faster responses for straightforward tasks. This is the default.
* `medium` — More reasoning for tasks with several constraints.
* `high` — The most reasoning for difficult analysis.
Available models:
* o4-mini
* o3
* o3-mini
If model-specific controls disappear after you change models, the node has
switched control sets. Standard and reasoning controls are mutually exclusive.
## Outputs
When **Structured Output** is off, the node has one output:
| Output | Type | Description |
| ------------ | ------ | -------------------------------- |
| **Response** | String | The model's complete text reply. |
When **Structured Output** is on, **Response** is replaced by:
| Output | Type | Description |
| ----------------------- | ------ | ------------------------------------------- |
| **Structured Response** | Object | The parsed object described by your schema. |
You can expose schema properties as individual outputs, then connect only
the values a later action needs.
## Return structured data
Structured output is useful when later actions need predictable fields instead
of prose. For example, this schema turns a support message into a summary,
priority, and category:
```json theme={null}
{
"type": "object",
"properties": {
"summary": {
"type": "string",
"description": "A one-sentence summary of the request"
},
"priority": {
"type": "string",
"enum": ["low", "normal", "high"]
},
"category": {
"type": "string",
"enum": ["billing", "bug", "question"]
}
},
"required": ["summary", "priority", "category"],
"additionalProperties": false
}
```
Turn on **Structured Output**. The **JSON Schema** input and **Structured
Response** output appear, while the text **Response** output is removed.
Paste a valid JSON schema into **JSON Schema**. It must parse as JSON and
contain an outer `type` of `object` with a `properties` map.
Use **Add detected properties to output** on the node to add `summary`,
`priority`, and `category` as connectable properties.
Route `priority` into conditional logic, store `category`, or send `summary`
in a notification without parsing a text response.
Enabling structured output changes the node's output from **Response** to
**Structured Response**. Check downstream connections when you toggle this
setting on an existing workflow.
## Work with files
Add one **Files** item for each image or PDF the model should inspect. Every
file is sent in the same user message as the prompt.
Good prompts state what to do with the attachments:
```text theme={null}
Compare the attached invoices. Return the vendor, invoice number, due date,
and total for each document. Flag any duplicate invoice numbers.
```
When structured output is enabled, describe the expected fields in the schema
instead of asking the model to invent a response format in the prompt.
## Example: triage a support request
Use Chat in the middle of a workflow to turn an incoming message into fields
that other actions can route:
1. Pass the new support message to **OpenAI: Chat**.
2. Connect the returned `category` to **Choose Value by Case**.
3. From each case, send the message to the matching support queue.
Configure the node with:
* **Prompt** — The incoming subject and message body.
* **System Prompt** — `Classify the request using only the supplied message.`
* **Structured Output** — On.
* **JSON Schema** — The support-triage schema above.
The routing action can use `category` directly, while notifications and logs
can use `summary` and `priority`.
## Troubleshooting
Check that the value is valid JSON, the outer `type` is `object`, and
`properties` is an object. JSON does not allow comments or trailing commas.
You selected a reasoning model. Choose a standard model to use **Web Search**
or **Temperature**.
**Structured Output** is enabled. The node now returns **Structured Response**
instead of **Response**.
Chat does not preserve conversation history. Include the required history
in the current prompt or load it from another action before Chat runs.
# Classify Text
Source: https://learn.workflow.dog/reference/actions/openai/classify
Assign text to one or more categories with OpenAI.
**Classify Text** maps a string to categories you define. It returns both the
selected category name and a boolean output for every configured category, so
downstream branches do not need to compare strings.
## Inputs
| Input | Type | Required | Description |
| ----------------------------- | -------------- | -------- | ------------------------------------------------------------------- |
| **Third-party account** | OpenAI account | Yes | The API key used for classification. |
| **Model** | OpenAI model | Yes | Defaults to GPT-5 Mini. |
| **Text** | String | Yes | The content to classify. |
| **Include 'Other' Category** | Boolean | No | Adds `other` for text that matches none of the supplied categories. |
| **Allow Multiple Categories** | Boolean | No | Lets more than one category be selected. |
| **Categories** | List | Yes | At least two key/description entries in the current implementation. |
Each category contains:
* **Key** — The exact string returned by the model.
* **Description** — Optional guidance that distinguishes this category.
Category keys must be unique. Use short, stable keys such as `billing` or
`security`; put nuance in the description.
## Outputs
**Selected Category** contains one category key. Each configured category
also creates an **Is "key"** boolean output.
**Selected Categories** contains a list of keys. Every **Is "key"** output
indicates whether that category was selected.
When **Include 'Other' Category** is on, **Is Other** is also available.
## Example: route inbound email
| Key | Description |
| --------- | ---------------------------------------------- |
| `billing` | Invoices, charges, refunds, or payment methods |
| `bug` | Something is broken or behaves unexpectedly |
| `sales` | Pricing, evaluation, or purchase questions |
Enable **Other** so unrelated messages have a safe route. Leave multiple
categories off when every email must have one owning queue.
# Extract Text
Source: https://learn.workflow.dog/reference/actions/openai/extract
Pull a configured set of text fields from unstructured content.
**Extract Text** asks OpenAI to find specific features in a source string. It
creates one output for every feature, in the same order as the feature list.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ----------------------------------------------------- |
| **Third-party account** | OpenAI account | Yes | The API key used for extraction. |
| **Model** | OpenAI model | Yes | Defaults to GPT-5 Mini. |
| **Text** | String | Yes | The unstructured source content. |
| **Features** | List of strings | Yes | One or more unique values describing what to extract. |
Example features for an invoice:
* `vendor name`
* `invoice number`
* `total amount with currency`
* `payment due date in ISO format`
## Outputs
The action creates **Extracted Feature 1**, **Extracted Feature 2**, and later
outputs that line up with the feature inputs. An output is empty when the model
cannot find that feature.
Do not repeat a feature. Duplicate feature strings cause the action to fail.
Include the desired format in the feature description. “Due date” may return
prose; “due date in `YYYY-MM-DD` format” is easier for later actions to use.
# Generate Image
Source: https://learn.workflow.dog/reference/actions/openai/generate-image
Create an image from a prompt with DALL·E or GPT Image.
**Generate Image** sends a text prompt to an OpenAI image model and returns the
generated image as a file. Available controls change with the selected model.
## Common inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | --------------------------------------------------------- |
| **Third-party account** | OpenAI account | Yes | The API key used for generation. |
| **Prompt** | String | Yes | A visual description of the desired image. |
| **Model** | Enum | Yes | DALL·E 2, DALL·E 3, or GPT Image 1. Defaults to DALL·E 2. |
| **Image Size** | Enum | Yes | The available dimensions for the selected model. |
## Model controls
Square sizes: `256×256`, `512×512`, and `1024×1024`. The default is
`1024×1024`.
Sizes: `1024×1024`, `1792×1024`, and `1024×1792`.
* **Quality** — Standard or HD.
* **Style** — Natural or Vivid.
Sizes: `1024×1024`, `1536×1024`, `1024×1536`, or Auto.
* **Quality** — Auto, High, Medium, or Low.
* **Background** — Auto, Transparent, or Opaque.
* **Output Format** — PNG, JPEG, or WebP.
* **Output Compression** — `0` to `100` for JPEG and WebP.
## Output
| Output | Type | Description |
| --------- | ---- | ------------------------------------------------------------------------------- |
| **Image** | File | The generated image. DALL·E output is PNG; GPT Image follows **Output Format**. |
Describe the subject, setting, composition, lighting, palette, and intended
use. A specific art direction is more reliable than a list of adjectives.
Transparent backgrounds are a GPT Image 1 feature. Choose PNG or WebP when the
downstream workflow must preserve transparency.
# Produce Text
Source: https://learn.workflow.dog/reference/actions/openai/produce
Generate one clean text result for each prompt.
**Produce Text** takes a list of prompts and returns one separate string for
each. The model is instructed to provide only the requested text without extra
commentary.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------ |
| **Third-party account** | OpenAI account | Yes | The API key used for generation. |
| **Model** | OpenAI model | Yes | Defaults to GPT-5 Mini. |
| **Prompts** | List of strings | Yes | One or more generation instructions. |
## Outputs
Each prompt creates a corresponding **Produced Text 1**, **Produced Text 2**,
and later output. All prompts are sent in one model request, but each result is
returned through its own connection.
## Example
Use three prompts to generate:
1. A subject line under 50 characters.
2. A two-sentence summary of the source text.
3. A short call to action.
Connect each produced output to the field that needs it.
Use **Chat** instead when you need one response that synthesizes several
instructions or must return a structured object.
# Transcribe Audio
Source: https://learn.workflow.dog/reference/actions/openai/transcribe
Convert an audio file to text with OpenAI.
**Transcribe Audio** sends an audio file to an OpenAI transcription model and
returns the recognized speech as one string.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------------------------------------------------- |
| **Third-party account** | OpenAI account | Yes | The API key used for transcription. |
| **Audio** | Audio file | Yes | A file whose MIME type begins with `audio/`. |
| **Model** | Enum | Yes | Whisper-1, GPT-4o Transcribe, or GPT-4o Mini Transcribe. Defaults to Whisper-1. |
## Output
| Output | Type | Description |
| -------- | ------ | ------------------------ |
| **Text** | String | The complete transcript. |
This action returns plain transcript text. It does not expose timestamps,
speaker labels, or segment metadata.
Preserve the source file's correct audio MIME type. A video file containing
audio is not accepted unless another action first extracts or converts it to
an audio file.
# Text to Speech
Source: https://learn.workflow.dog/reference/actions/openai/tts
Turn text into a spoken audio file with OpenAI.
**Text to Speech** generates spoken audio from a string. Choose a voice, speed,
model, and file format, then connect the resulting file to storage, email, or
another media action.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ---------------------------------------------------------------------------- |
| **Third-party account** | OpenAI account | Yes | The API key used for synthesis. |
| **Text** | String | Yes | The content to speak. |
| **Model** | Enum | Yes | TTS-1, TTS-1 HD, or GPT-4o Mini TTS. Defaults to TTS-1. |
| **Voice** | Enum | Yes | Alloy, Ash, Ballad, Coral, Echo, Fable, Onyx, Nova, Sage, Shimmer, or Verse. |
| **Speed** | Number | No | From `0.25×` to `4×`. Defaults to `1×`. |
| **Response Format** | Enum | Yes | MP3, Opus, AAC, FLAC, or PCM. Defaults to MP3. |
| **Instructions** | String | No | Delivery direction available only for GPT-4o Mini TTS. |
Example instructions:
```text theme={null}
Speak warmly and clearly, with a brief pause after each sentence.
```
## Output
| Output | Type | Description |
| --------- | ---- | ----------------------------------------------------------------- |
| **Audio** | File | The generated audio, named from the first part of the input text. |
Use TTS-1 for a general-purpose result, TTS-1 HD when fidelity matters more,
or GPT-4o Mini TTS when you need explicit delivery instructions.
# Delete Message
Source: https://learn.workflow.dog/reference/actions/outlook/delete-message
Move an Outlook message to Deleted Items or permanently delete it.
The **Delete Message** action removes one Outlook message. By default, Microsoft
moves it to Deleted Items; permanent deletion bypasses that recoverable step.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ----------------- | -------- | ------------------------------------------ |
| **Third-party account** | Microsoft account | Yes | Outlook account containing the message. |
| **Message ID** | String | Yes | Microsoft ID of the message. |
| **Permanent Delete** | Boolean | No | Bypass Deleted Items. Defaults to `false`. |
**Permanent Delete** is destructive and the action returns no output. Leave it
off when the message may need to be recovered.
# Draft Email
Source: https://learn.workflow.dog/reference/actions/outlook/draft-email
Create an unsent email draft in Microsoft Outlook.
The **Draft Email** action saves a new message in Outlook without sending it.
Recipients, subject, and body can be left empty for a person to complete later.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | ------------------------------------------ |
| **Third-party account** | Microsoft account | Yes | Outlook account that owns the draft. |
| **Recipients** | List of email strings | No | `To` addresses. |
| **CC** | List of email strings | No | Carbon-copy addresses. |
| **Subject** | String | No | Draft subject. Defaults to empty. |
| **Body** | String | No | Draft content. Defaults to empty. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files included in the draft. |
## Outputs
| Output | Type | Description |
| ------------------- | ------ | ----------------------------------- |
| **Message ID** | String | Immutable ID of the created draft. |
| **Conversation ID** | String | Conversation assigned to the draft. |
## Example
To prepare an account summary for review:
1. Generate the summary with an earlier action.
2. Use the generated text as the Outlook draft's **Body**.
3. After the draft is created, notify the account owner that it is ready to
review.
# Draft Reply
Source: https://learn.workflow.dog/reference/actions/outlook/draft-reply
Create an unsent reply or reply-all draft in Outlook.
The **Draft Reply** action creates a threaded Outlook reply without sending it.
Use it when a person needs to review, edit, or approve the response.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | ------------------------------------------ |
| **Third-party account** | Microsoft account | Yes | Outlook account that owns the draft. |
| **Message ID** | String | Yes | Message being answered. |
| **Reply All** | Boolean | No | Include Outlook's reply-all recipients. |
| **Body** | String | No | Draft content. Defaults to empty. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files attached to the reply draft. |
## Outputs
| Output | Type | Description |
| ------------ | ------ | -------------------------------- |
| **Draft ID** | String | Immutable ID of the reply draft. |
Review recipients before sending a draft created with **Reply All**.
# Forward
Source: https://learn.workflow.dog/reference/actions/outlook/forward
Forward an Outlook message with optional content and attachments.
The **Forward** action creates and sends a forward of an existing Outlook
message. You can add new content and additional attachments.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | ----------------------------------------------- |
| **Third-party account** | Microsoft account | Yes | Outlook account that sends the forward. |
| **Message ID** | String | Yes | Microsoft ID of the original message. |
| **Recipients** | List of email strings | Yes | One or more destination addresses. |
| **Body** | String | No | Additional content included with the forward. |
| **Body Type** | `Plain Text` or `HTML` | No | Encoding for the additional body. Default text. |
| **Attachments** | List of files | No | Additional files to include. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | ------------------------------------------ |
| **Forward ID** | String | Immutable ID created for the sent forward. |
**Attachments** adds new files to the forward. Outlook itself constructs the
forwarded-message content from the source Message ID.
# Get Conversation
Source: https://learn.workflow.dog/reference/actions/outlook/get-conversation
Load every message in an Outlook conversation from oldest to newest.
The **Get Conversation** action retrieves every mailbox message with a matching
Outlook conversation ID. It follows Microsoft pagination, sorts messages by
received time, and returns the complete conversation oldest first.
## Inputs
| Input | Type | Required | Description |
| ------------------------ | ----------------- | -------- | ---------------------------------------------------------- |
| **Third-party account** | Microsoft account | Yes | Account whose mailbox is searched. |
| **Conversation ID** | String | Yes | Outlook conversation ID from a trigger, draft, or message. |
| **Download Attachments** | Boolean | No | Download files for every message. Defaults to `false`. |
Leave attachment downloading off when you only need conversation text. It adds
a request for each message that reports attachments.
## Outputs
**Messages** is a list ordered from oldest to newest. Each item includes:
| Field | Type | Description |
| ------------------- | ------------- | ------------------------------------------- |
| **Message ID** | String | Microsoft message ID. |
| **Conversation ID** | String | Conversation ID returned by Microsoft. |
| **Sender Name** | String | Sender display name. |
| **Sender Address** | String | Sender email address. |
| **Subject** | String | Message subject. |
| **Plain Text** | String | Body requested as text. |
| **HTML** | String | Body requested as HTML. |
| **Date/Time** | Date | Received time. |
| **Is Read** | Boolean | Outlook read state. |
| **Attachments** | List of files | Available only when downloading is enabled. |
Toggling **Download Attachments** changes the nested output shape by adding or
removing **Attachments**. Check downstream connections after changing it.
## Troubleshooting
Trimmed Conversation ID matching is exact. Confirm the ID comes from the
same Microsoft mailbox and has not been confused with a Message ID.
# Get Message
Source: https://learn.workflow.dog/reference/actions/outlook/get-message
Retrieve message content and metadata from Microsoft Outlook.
The **Get Message** action loads one Outlook message by its Microsoft message
ID. It requests the message twice so both plain-text and HTML body forms are
available.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ----------------- | -------- | --------------------------------- |
| **Third-party account** | Microsoft account | Yes | Account used to read the message. |
| **Message ID** | String | Yes | Microsoft ID of the message. |
## Outputs
| Output | Type | Description |
| ------------------- | ------------- | -------------------------------------------- |
| **Sender Name** | String | Sender display name, when present. |
| **Sender Address** | String | Sender email address, when present. |
| **Subject** | String | Message subject. |
| **Plain Text** | String | Message body requested as text. |
| **HTML** | String | Message body requested as HTML. |
| **Attachments** | List of files | Attachment output; currently returned empty. |
| **Date/Time** | Date | Time the message was received. |
| **Is Read** | Boolean | Current Outlook read state. |
| **Conversation ID** | String | Conversation containing the message. |
The current Get Message node does not expose attachment downloading, so
**Attachments** is an empty list. The **New Email** trigger downloads
attachments, and **Get Conversation** can download them when enabled.
## Example
Connect a stored Outlook message ID to **Get Message**. The action returns the
message's **Conversation ID**, which you can pass to **Get Conversation** when
you need the rest of the conversation.
# Mark as Read
Source: https://learn.workflow.dog/reference/actions/outlook/mark-as-read
Mark one Microsoft Outlook message as read.
The **Mark as Read** action sets an Outlook message's read state to `true`.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ----------------- | -------- | --------------------------------------- |
| **Third-party account** | Microsoft account | Yes | Outlook account containing the message. |
| **Message ID** | String | Yes | Microsoft ID of the message to update. |
This action returns no output. Use **Get Message** when a later branch needs
the current **Is Read** value.
# Mark as Unread
Source: https://learn.workflow.dog/reference/actions/outlook/mark-as-unread
Mark one Microsoft Outlook message as unread.
The **Mark as Unread** action sets an Outlook message's read state to `false`.
Use it to return processed mail to a person's attention.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ----------------- | -------- | --------------------------------------- |
| **Third-party account** | Microsoft account | Yes | Outlook account containing the message. |
| **Message ID** | String | Yes | Microsoft ID of the message to update. |
This action changes the message and returns no output.
# Send Reply
Source: https://learn.workflow.dog/reference/actions/outlook/reply
Send a reply or reply-all to a Microsoft Outlook message.
The **Send Reply** action creates a reply draft for a message, adds the supplied
body and attachments, then sends it.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | --------------------------------------------- |
| **Third-party account** | Microsoft account | Yes | Outlook account that sends the reply. |
| **Message ID** | String | Yes | Microsoft ID of the message being answered. |
| **Reply All** | Boolean | No | Include the original conversation recipients. |
| **Body** | String | Yes | Reply content. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files to attach to the reply. |
## Outputs
| Output | Type | Description |
| ------------ | ------ | ---------------------------------------- |
| **Reply ID** | String | Immutable ID created for the sent reply. |
**Reply All** can send the response to every recipient selected by Outlook.
Leave it off for a reply only to the original sender.
# Send Email
Source: https://learn.workflow.dog/reference/actions/outlook/send-email
Send a plain-text or HTML email from Microsoft Outlook.
The **Send Email** action creates and sends a message from a connected Microsoft
account. It supports multiple recipients, CC addresses, and file attachments.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------------- | -------- | ------------------------------------------ |
| **Third-party account** | Microsoft account | Yes | Outlook account that sends the message. |
| **Recipients** | List of email strings | Yes | One or more `To` addresses. |
| **CC** | List of email strings | No | Carbon-copy addresses. |
| **Subject** | String | Yes | Message subject. |
| **Body** | String | Yes | Plain-text or HTML content. |
| **Body Type** | `Plain Text` or `HTML` | No | Body encoding. Defaults to **Plain Text**. |
| **Attachments** | List of files | No | Files attached to the message. |
## Outputs
| Output | Type | Description |
| ------------------- | ------ | -------------------------------------------- |
| **Message ID** | String | Immutable Microsoft ID for the sent message. |
| **Conversation ID** | String | Outlook conversation containing the message. |
The action first creates a draft with an immutable ID, then sends that draft.
Store **Conversation ID** when later steps need the complete thread.
Set **Body Type** to **HTML** before supplying markup. Untrusted values should
be escaped or sanitized before they are inserted into HTML.
# Run Query
Source: https://learn.workflow.dog/reference/actions/postgres/run-query
Execute a parameterized SQL query on PostgreSQL.
**Run Query** connects to a PostgreSQL account, executes one SQL statement, and
returns its result rows and affected-row count.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------------------ | -------- | ------------------------------------------------------------------ |
| **Third-party account** | PostgreSQL account | Yes | Host, database, credentials, port, and SSL settings. |
| **Query** | String | Yes | A non-empty SQL statement. |
| **Parameters** | List of any values | No | Values bound to `$1`, `$2`, `$3`, and later placeholders in order. |
```sql theme={null}
select id, email
from customers
where plan = $1 and created_at >= $2
order by created_at desc;
```
Add `pro` as parameter 1 and the cutoff date as parameter 2.
Use parameters for values instead of joining untrusted text into SQL.
Parameter placeholders protect values, but they cannot stand in for table or
column names.
## Outputs
| Output | Type | Description |
| ------------- | --------------- | ------------------------------------------------------------------ |
| **Rows** | List of objects | Rows returned by the query. Each object uses column names as keys. |
| **Row Count** | Number | The number of rows returned or affected. |
The database connection is closed after the query succeeds or fails.
# Create Contact
Source: https://learn.workflow.dog/reference/actions/resend/create-contact
Add a contact to a Resend audience.
**Create Contact** adds an email address and optional name to a Resend audience.
| Input | Type | Required | Description |
| ------------------------------ | -------------- | -------- | -------------------------------------------------- |
| **Third-party account** | Resend account | Yes | The API key used for the audience. |
| **Audience ID** | String | Yes | The destination audience. |
| **Email** | Email | Yes | The contact's address. |
| **First Name** / **Last Name** | String | No | Optional contact name fields. |
| **Subscribed** | Boolean | No | Whether the contact is subscribed. Defaults to on. |
| Output | Type | Description |
| -------------- | ------ | ---------------------------------------- |
| **Contact ID** | String | Resend's identifier for the new contact. |
# Delete Contact
Source: https://learn.workflow.dog/reference/actions/resend/delete-contact
Permanently remove a contact from a Resend audience.
**Delete Contact** permanently removes one contact from one Resend audience.
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | --------------------------------------------------- |
| **Third-party account** | Resend account | Yes | The API key used for the audience. |
| **Audience ID** | String | Yes | The audience containing the contact. |
| **Contact ID or Email** | String | Yes | Resend's contact ID or the contact's email address. |
Deletion is different from unsubscribing. Use **Unsubscribe Contact** when the
record should remain in the audience with an opted-out state.
# Get Email by ID
Source: https://learn.workflow.dog/reference/actions/resend/retrieve-email
Retrieve a Resend email and its latest delivery event.
**Get Email by ID** fetches the stored message details for a Resend email.
## Input
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ----------------------------------------------------- |
| **Third-party account** | Resend account | Yes | The account that sent the email. |
| **Email ID** | String | Yes | A non-empty ID returned by a send or schedule action. |
## Outputs
| Output | Type | Description |
| --------------------------------------------- | ---------------- | ------------------------------------------------------------- |
| **Email ID** | String | The email identifier. |
| **From** | String | The sender. |
| **Recipients**, **CC**, **BCC**, **Reply To** | Lists of strings | Message recipients. |
| **Subject** | String | The subject line. |
| **HTML** / **Plain Text** | String | Message content; either can be empty if it was not provided. |
| **Created At** | Date | When the email was created. |
| **Last Event** | String | The latest Resend event, such as sent, delivered, or bounced. |
**Last Event** is a status value, not a timestamp. Use it to branch on the
latest known delivery state.
# Schedule Email
Source: https://learn.workflow.dog/reference/actions/resend/schedule-email
Schedule a Resend email for a future time.
**Schedule Email** creates a Resend email with a future send time.
## Inputs
The message fields match **Send Email**: **From**, one or more **Recipients**,
**Subject**, **HTML Content**, optional **Plain Text**, **CC**, **BCC**, and
**Reply To**.
**Schedule Time** is required and accepts either:
* Natural language such as `in 1 hour` or `tomorrow at 3pm`.
* An ISO 8601 timestamp such as `2026-08-05T15:00:00Z`.
## Output
| Output | Type | Description |
| ------------ | ------ | -------------------------------------------- |
| **Email ID** | String | Resend's identifier for the scheduled email. |
Natural-language times can be ambiguous. Use an ISO 8601 timestamp with an
explicit offset or `Z` when the exact timezone matters.
# Send Email
Source: https://learn.workflow.dog/reference/actions/resend/send-email
Send a transactional email immediately with Resend.
Resend **Send Email** sends an HTML email immediately, with optional text,
copy recipients, reply-to addresses, and tracking tags.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ------------------------ | -------- | ------------------------------------------------- |
| **Third-party account** | Resend account | Yes | The API key used to send. |
| **From** | String | Yes | A sender such as `Acme `. |
| **Recipients** | List of emails | Yes | One or more destination addresses. |
| **CC** / **BCC** | Lists of emails | No | Copy recipients. |
| **Subject** | String | Yes | A non-empty subject. |
| **HTML Content** | String | Yes | The HTML message body. |
| **Plain Text** | String | No | A text-only alternative. |
| **Reply To** | List of strings | No | Addresses that receive replies. |
| **Tags** | List of name/value pairs | No | Resend metadata for categorization. |
Tag names and values should contain only letters, numbers, underscores, and
dashes.
## Output
| Output | Type | Description |
| ------------ | ------ | --------------------------------- |
| **Email ID** | String | Resend's identifier for the send. |
Store **Email ID** when a later action must retrieve delivery details.
# Unsubscribe Contact
Source: https://learn.workflow.dog/reference/actions/resend/unsubscribe-contact
Opt a contact out of a Resend audience.
**Unsubscribe Contact** changes an existing Resend contact to unsubscribed
without deleting the contact record.
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | --------------------------------------------------- |
| **Third-party account** | Resend account | Yes | The API key used for the audience. |
| **Audience ID** | String | Yes | The audience containing the contact. |
| **Contact ID or Email** | String | Yes | Resend's contact ID or the contact's email address. |
The action has no output and continues after Resend confirms the update.
# Scrape URL
Source: https://learn.workflow.dog/reference/actions/scrapfly/scrape
Extract page content through Scrapfly with rendering and anti-bot controls.
**Scrape URL** retrieves a page through Scrapfly and can render JavaScript,
bypass anti-scraping protection, reuse a browser session, and execute custom
JavaScript before returning content.
## Inputs
| Input | Type | Required | Description |
| ---------------------------- | ------------------------ | -------- | ----------------------------------------------------------------------------------------------------------- |
| **Third-party account** | Scrapfly account | Yes | The Scrapfly API key. |
| **URL** | String | Yes | The page to scrape. |
| **Format** | Enum | Yes | Raw HTML, clean HTML, plain text, Markdown, Markdown without links/images, or JSON. Defaults to clean HTML. |
| **Anti-Scraping Protection** | Boolean | No | Enable Scrapfly's anti-bot handling. |
| **Render JavaScript** | Boolean | No | Use browser rendering. Defaults to on. |
| **Session** | String | No | An alphanumeric session name, up to 255 characters, used to reuse cookies, fingerprint, and proxy. |
| **Cache** | Boolean | No | Reuse eligible cached results. |
| **Proxy Pool** | Enum | No | Datacenter or residential proxies. |
| **Proxy Country** | String | No | Scrapfly's country-location value. |
| **Operating System** | Enum | No | Windows 11, macOS, Linux, or Chrome OS. Random when omitted. |
| **Headers** | List of name/value pairs | No | Custom request headers. Header names are sent lowercase. |
### JavaScript rendering controls
These inputs appear only while **Render JavaScript** is on:
| Input | Type | Description |
| --------------------- | ------- | --------------------------------------------------------- |
| **Rendering Wait** | Number | Milliseconds to wait after page load. Defaults to `1000`. |
| **JavaScript Code** | String | Browser-side code executed after the rendering wait. |
| **Wait For Selector** | String | CSS selector to wait for after custom JavaScript runs. |
| **Auto Scroll** | Boolean | Scroll to load viewport-triggered content. |
## Outputs
| Output | Type | Description |
| --------------------- | ------ | ------------------------------------------------------------------------ |
| **Content** | String | Page content in the selected format. |
| **Status Code** | Number | The page's HTTP status. |
| **Final URL** | String | The final URL after redirects. |
| **JavaScript Result** | Any | The return value from custom code; shown only with JavaScript rendering. |
Start with clean HTML and JavaScript rendering on. Enable anti-scraping
protection, a residential proxy, or a session only when the target requires
them, since advanced Scrapfly features can affect request cost.
# Take Screenshot
Source: https://learn.workflow.dog/reference/actions/scrapfly/screenshot
Capture a rendered webpage as an image with Scrapfly.
**Take Screenshot** renders a URL through Scrapfly and returns a screenshot
file. It supports viewport, full-page, vertical-scroll, and element-specific
capture.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ------------------------------------------------------------------- |
| **Third-party account** | Scrapfly account | Yes | The Scrapfly API key. |
| **URL** | String | Yes | The page to capture. |
| **Format** | Enum | Yes | JPEG, PNG, WebP, or GIF. Defaults to WebP in the editor. |
| **Capture** | Enum | Yes | Viewport, full page, or vertical scroll. Defaults to viewport. |
| **Element Selector** | String | No | CSS selector or XPath. Overrides **Capture**. |
| **Width** / **Height** | Number | No | Browser dimensions from `100` to `4096`. Defaults to `1920 × 1080`. |
| **Dark Mode** | Boolean | No | Request a dark color scheme. |
| **Block Banners** | Boolean | No | Hide cookie banners and covering overlays. |
| **Print Media Format** | Boolean | No | Render print CSS. |
| **Auto Scroll** | Boolean | No | Scroll to load dynamic content. |
| **Wait For Selector** | String | No | Wait for a CSS selector or XPath before capture. |
| **Rendering Wait** | Number | No | Additional milliseconds after load. Defaults to `1000`. |
| **Proxy Country** | String | No | Scrapfly's proxy-country value. |
| **Cache** | Boolean | No | Reuse eligible cached captures. |
## Output
| Output | Type | Description |
| -------------- | ---------- | ------------------------------------------------- |
| **Screenshot** | Image file | The captured image, named from the page hostname. |
**Element Selector** replaces the capture mode rather than cropping the
finished full-page image.
## Troubleshooting
Enable **Auto Scroll**, add **Wait For Selector**, or increase **Rendering
Wait** so the page can finish loading before capture.
Enable **Block Banners**. If the target uses a custom overlay, capture a
specific element or use **Scrape URL** with custom JavaScript.
# Balanced Select
Source: https://learn.workflow.dog/reference/actions/selector/balanced
Choose the option with the lowest current balance.
**Balanced Select** favors the least-used option. It can track balances for
this node automatically or use counts supplied by the workflow.
## Modes
Add one or more **Options** and leave **Manage state internally?** enabled.
The node stores a balance for each option within the project, selects the
first option with the lowest balance, then adds **Increment** to that
option's balance.
| Input | Type | Required | Description |
| ------------- | -------------- | -------- | ---------------------------------------------- |
| **Options** | Repeatable any | Yes | Values to distribute selections across. |
| **Increment** | Number | No | Amount added after selection. Defaults to `1`. |
Disable **Manage state internally?** when counts come from a database,
queue, or another workflow action.
Each **Option** has:
* **Value** — The value that can be selected.
* **Current Balance** — Its current numeric amount.
The action returns the first option with the lowest balance. It does not
update externally provided balances.
## Output
| Output | Type | Description |
| ------------ | ---- | ------------------------------------------ |
| **Selected** | Any | The value belonging to the lowest balance. |
In managed mode, balances belong to this node instance and are stored by
option position. Reordering, adding, or removing options can associate
existing counts with different values.
Simultaneous runs can inspect the same stored balance before either update is
saved. If strict one-at-a-time distribution is required, serialize runs or
provide balances from a transactional external source.
# Random Select
Source: https://learn.workflow.dog/reference/actions/selector/random
Choose one option at random on each run.
## Input
| Input | Type | Required | Description |
| ----------- | -------------- | -------- | ---------------------------------------- |
| **Options** | Repeatable any | Yes | At least one value that may be selected. |
## Output
| Output | Type | Description |
| ------------ | ---- | ----------------------------- |
| **Selected** | Any | One randomly selected option. |
Every position has the same probability. Duplicate values occupy multiple
positions and therefore increase that value's chance of selection.
Random selection is nondeterministic. Two runs with the same options can
return different results.
# Round Robin
Source: https://learn.workflow.dog/reference/actions/selector/round-robin
Cycle through options in order across workflow runs.
**Round Robin** returns the first option on its first run, the second on its
next run, and wraps back to the beginning after the last option.
## Input
| Input | Type | Required | Description |
| ----------- | -------------- | -------- | ------------------------------------- |
| **Options** | Repeatable any | Yes | At least one value in rotation order. |
## Output
| Output | Type | Description |
| ------------ | ---- | ----------------------------------------- |
| **Selected** | Any | The option at the current rotation index. |
The current index is stored for this node instance within the project. With
`[A, B, C]`, successive runs return `A`, `B`, `C`, `A`.
Changing the number or order of options does not reset the stored index. The
next run applies that index to the new list.
Simultaneous runs can read the same index before either saves the next one.
Serialize runs when each option must be chosen exactly once per cycle.
# Collapse Whitespace
Source: https://learn.workflow.dog/reference/actions/text/collpase-whitespace
Limit consecutive spaces and line breaks while preserving the text.
The **Collapse Whitespace** action shortens runs of spaces and line breaks to
configurable maximums. Use it to clean copied text without removing all
paragraph structure.
The source filename intentionally uses `collpase-whitespace`. The action shown
in the workflow builder is named **Collapse Whitespace**.
## Inputs
| Input | Type | Required | Description |
| --------------------- | ------- | -------- | ------------------------------------------------------------------------- |
| **Text** | String | Yes | The text to clean. |
| **Collapse Spaces** | Boolean | No | Limits runs of literal space characters. Defaults to `true`. |
| **Max Spaces** | Number | No | Maximum spaces left in a run. Must be non-negative; defaults to `1`. |
| **Collapse Newlines** | Boolean | No | Limits consecutive line breaks. Defaults to `true`. |
| **Max Newlines** | Number | No | Maximum line breaks left in a run. Must be non-negative; defaults to `2`. |
## Outputs
| Output | Type | Description |
| ------------- | ------ | ----------------------------------------------- |
| **Collapsed** | String | The text after the selected limits are applied. |
## How the limits work
Only runs longer than the configured maximum are changed. With the defaults:
* Two or more consecutive spaces become one space.
* Three or more consecutive line breaks become two line breaks.
* Tabs and other whitespace are left unchanged.
* Windows-style `\r\n` line breaks are normalized to `\n` only when a run is
collapsed.
Set a maximum to `0` to remove matching runs entirely. Turn either collapse
toggle off to preserve that kind of whitespace regardless of its maximum.
Use **Trim Whitespace** after this action if leading or trailing whitespace
should also be removed.
# Contains Text
Source: https://learn.workflow.dog/reference/actions/text/contains-text
Check whether one piece of text appears anywhere inside another.
The **Contains Text** action searches a string for an exact piece of text and
returns a boolean. Use it to route workflows based on keywords, identifiers, or
short phrases.
## Inputs
| Input | Type | Required | Description |
| --------------- | ------- | -------- | ---------------------------------------------------------------- |
| **Text** | String | Yes | The text to search. |
| **Search** | String | Yes | The exact sequence of characters to find. |
| **Ignore Case** | Boolean | No | Compares lowercase versions of both values. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------------------- |
| **Result** | Boolean | `true` when **Search** occurs in **Text**; otherwise `false`. |
## Example
With **Text** set to `Order REF-204 is ready` and **Search** set to `ref-204`,
the result is `false`. Turn on **Ignore Case** to return `true`.
The search is literal. Characters such as `.`, `*`, and `?` have no special
meaning. Use **Matches Regex** when you need pattern matching.
# Count Occurrences
Source: https://learn.workflow.dog/reference/actions/text/count-occurrences
Count literal text or regular-expression matches inside a string.
The **Count Occurrences** action counts how many times a literal string or
regular-expression separator appears in text. Switch **Use Regex** to choose
the matching mode.
## Inputs
| Input | Type | Required | Description |
| ------------------ | ------------------ | --------- | ------------------------------------------------------------- |
| **Text** | String | Yes | The text to search. |
| **Use Regex** | Boolean | Yes | Shows either the literal-text or regex inputs. |
| **Search Text** | String | Sometimes | The literal text to count when **Use Regex** is off. |
| **Ignore Case** | Boolean | No | Makes literal matching case-insensitive. Defaults to `false`. |
| **Search Pattern** | Regular expression | Sometimes | The pattern used when **Use Regex** is on. |
## Outputs
| Output | Type | Description |
| --------- | ------ | -------------------------------- |
| **Count** | Number | The number of occurrences found. |
## Choose a matching mode
Literal mode searches for the exact characters in **Search Text**. Turn on
**Ignore Case** to compare lowercase versions of the text and search value.
With **Text** set to `Error: error: ERROR` and **Search Text** set to
`error`, the count is `1` by default or `3` when case is ignored.
Regex mode accepts a value from **Regular Expression**. Use a pattern when
the matching text varies, such as `INV-\d+`.
Regex flags are preserved. A case-insensitive pattern can count different
letter cases without using the literal-mode **Ignore Case** option.
Avoid capture groups in the regex used for this action. The implementation
counts the pieces produced by splitting the text, and captured values are
included in that result. Use non-capturing groups such as `(?:foo|bar)` when
grouping is required.
The action counts non-overlapping occurrences. For example, searching for `aa`
in `aaa` returns `1`.
# Ends With
Source: https://learn.workflow.dog/reference/actions/text/ends-with
Check whether text finishes with a specific sequence of characters.
The **Ends With** action returns whether a string ends with an exact suffix.
It is useful for checking file extensions, domain endings, and naming
conventions.
## Inputs
| Input | Type | Required | Description |
| --------------- | ------- | -------- | ---------------------------------------------------------------- |
| **Text** | String | Yes | The text to check. |
| **Search** | String | Yes | The suffix expected at the end of the text. |
| **Ignore Case** | Boolean | No | Compares lowercase versions of both values. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------------------- |
| **Result** | Boolean | `true` when **Text** ends with **Search**; otherwise `false`. |
## Example
`report.PDF` ends with `.pdf` only when **Ignore Case** is enabled.
The action does not trim whitespace. A trailing space or line break is part of
the text and can cause an otherwise matching suffix to return `false`.
# Generate UUID
Source: https://learn.workflow.dog/reference/actions/text/generate-uuid
Create a random version 4 UUID.
The **Generate UUID** action creates a new random UUID v4 each time it runs.
Use the result as a correlation ID, idempotency key, temporary record ID, or
other workflow-scoped identifier.
## Outputs
| Output | Type | Description |
| -------- | ------ | ------------------------------------------ |
| **UUID** | String | A newly generated UUID in standard format. |
An output looks like:
```text theme={null}
3f2504e0-4f89-4d3a-9a0c-0305e82c3301
```
The action produces a different value on every run. Store the output if later
workflow steps or future runs need to reuse the same identifier.
# Is Email?
Source: https://learn.workflow.dog/reference/actions/text/is-email
Check whether text has a valid email-address format.
The **Is Email?** action validates the shape of an email address and returns a
boolean. Use it before routing or storing user-supplied contact data.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ------------------- |
| **Text** | String | Yes | The value to check. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ----------------------------------------------------------------- |
| **Result** | Boolean | `true` when the text has a valid email format; otherwise `false`. |
This checks syntax only. It does not verify that the address, domain, or
mailbox exists.
# Is Text?
Source: https://learn.workflow.dog/reference/actions/text/is-string
Check whether a workflow value is text.
The **Is Text?** action checks the runtime type of any value. It returns `true`
only for strings; it does not convert the value first.
## Inputs
| Input | Type | Required | Description |
| --------- | ---- | -------- | ------------------- |
| **Value** | Any | Yes | The value to check. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------- |
| **Result** | Boolean | `true` when **Value** is text; otherwise `false`. |
For example, `"42"` returns `true`, while the number `42` returns `false`.
# Is URL?
Source: https://learn.workflow.dog/reference/actions/text/is-url
Check whether text is a valid absolute URL.
The **Is URL?** action validates a string as a URL and returns a boolean. Use it
to guard actions that expect a complete link.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ------------------- |
| **Text** | String | Yes | The value to check. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------------- |
| **Result** | Boolean | `true` when the text is a valid URL; otherwise `false`. |
Supply a complete URL such as `https://example.com/report`. A hostname or
relative path by itself may not be accepted.
# Is UUID?
Source: https://learn.workflow.dog/reference/actions/text/is-uuid
Check whether text is a valid UUID.
The **Is UUID?** action validates a string as a UUID and returns a boolean.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ------------------- |
| **Text** | String | Yes | The value to check. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | -------------------------------------------------------- |
| **Result** | Boolean | `true` when the text is a valid UUID; otherwise `false`. |
The validator accepts standard UUID text such as
`3f2504e0-4f89-41d3-9a0c-0305e82c3301`. It is not limited to UUID v4.
# Join Text
Source: https://learn.workflow.dog/reference/actions/text/join
Combine multiple text values with an optional separator.
The **Join Text** action combines a repeatable collection of strings in order.
The separator is inserted between adjacent items, never before the first or
after the last.
## Inputs
| Input | Type | Required | Description |
| ------------- | --------------- | -------- | ----------------------------------------------------------------- |
| **Separator** | String | No | Text placed between items. Defaults to empty text. |
| **Texts** | List of strings | No | The ordered pieces to join. The node starts with two item inputs. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ---------------------------------- |
| **Joined** | String | All supplied text pieces combined. |
## Examples
| Texts | Separator | Joined |
| --------------------------- | ---------- | ------------------ |
| `red`, `green`, `blue` | `, ` | `red, green, blue` |
| `first line`, `second line` | Line Break | Two lines of text |
| `ACME`, `1042` | Empty | `ACME1042` |
Connect **Line Break** as the separator when building a message from several
paragraphs.
# Text Length
Source: https://learn.workflow.dog/reference/actions/text/length
Count the characters in a piece of text.
The **Text Length** action returns the number of JavaScript string units in the
input. Use it for minimum-length checks, limits, or simple text metrics.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | -------------------- |
| **Text** | String | Yes | The text to measure. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | -------------------------------------- |
| **Length** | Number | The measured length of the input text. |
Spaces and line breaks are counted. Some emoji and combined Unicode characters
can count as more than one unit.
# Lowercase
Source: https://learn.workflow.dog/reference/actions/text/lowercase
Convert every letter in a string to lowercase.
The **Lowercase** action converts text with JavaScript's standard lowercase
rules. Non-letter characters remain unchanged.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | -------------------- |
| **Text** | String | Yes | The text to convert. |
## Outputs
| Output | Type | Description |
| -------- | ------ | -------------------------------------- |
| **text** | String | The input text converted to lowercase. |
For example, `Invoice #A19` becomes `invoice #a19`.
# Matches Regex
Source: https://learn.workflow.dog/reference/actions/text/matches-regex
Test whether a regular expression matches any part of a string.
The **Matches Regex** action tests a string with a reusable **Regular
Expression** value. It returns `true` when the pattern finds a match anywhere
in the text.
## Inputs
| Input | Type | Required | Description |
| --------- | ------------------ | -------- | ------------------------------ |
| **Text** | String | Yes | The text to test. |
| **Regex** | Regular expression | Yes | The pattern used for the test. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | ------------------------------------------------- |
| **Result** | Boolean | `true` when the regex matches; otherwise `false`. |
## Match the entire value
Regex matching is not automatically anchored. A pattern of `\d+` returns
`true` for `Order 1042 shipped` because a substring matches. Add anchors when
the whole value must follow the pattern:
```text theme={null}
^\d+$
```
With that pattern, `1042` matches and `Order 1042` does not. Enable the
**Multiline** flag only when `^` and `$` should also apply to individual lines.
# Line Break
Source: https://learn.workflow.dog/reference/actions/text/newline
Create text containing a chosen number of line breaks.
The **Line Break** action returns a string made entirely of newline characters.
It is useful as a separator for **Join Text** or as the separator passed to
**Split Text**.
## Inputs
| Input | Type | Required | Description |
| --------- | ------ | -------- | --------------------------------------------- |
| **Count** | Number | No | A non-negative whole number. Defaults to `1`. |
## Outputs
| Output | Type | Description |
| -------- | ------ | -------------------------------------------------- |
| **Text** | String | A string containing exactly **Count** line breaks. |
Set **Count** to `2` to create a blank line between joined paragraphs. A count
of `0` returns an empty string.
# Random Text
Source: https://learn.workflow.dog/reference/actions/text/random
Generate a random string from selected character groups.
The **Random Text** action creates a string of a configured length. Choose
whether its characters may include uppercase letters, lowercase letters,
numbers, and symbols.
## Inputs
| Input | Type | Required | Description |
| --------------------- | ------- | -------- | ------------------------------------------------------------- |
| **Length** | Number | No | Positive whole-number output length. Defaults to `10`. |
| **Include Uppercase** | Boolean | No | Adds `A–Z` to the character set. Defaults to `true`. |
| **Include Lowercase** | Boolean | No | Adds `a–z` to the character set. Defaults to `true`. |
| **Include Numbers** | Boolean | No | Adds `0–9` to the character set. Defaults to `true`. |
| **Include Symbols** | Boolean | No | Adds `!@#$%^&*_-=` to the character set. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | -------------------------------------------------- |
| **Random** | String | A newly generated string of **Length** characters. |
The defaults produce a 10-character alphanumeric string such as `nQ7Lu0xP2a`.
Every enabled group contributes characters to one shared pool; the result is
not guaranteed to contain a character from every selected group.
Keep at least one character group enabled. With every group disabled, there
are no characters to choose from and the action cannot produce a result.
This action uses general-purpose pseudorandom selection. Do not use its output
as a password, authentication token, API secret, or other security-sensitive
credential.
# Regular Expression
Source: https://learn.workflow.dog/reference/actions/text/regex
Define a reusable regular-expression pattern and flags.
The **Regular Expression** action builds a regex value for other text actions.
Use it with **Matches Regex**, **Extract Text with Regex**, **Replace Text**,
**Split Text**, or **Count Occurrences**.
## Inputs
| Input | Type | Required | Description |
| ----------- | ------ | -------- | -------------------------------------------------------------------- |
| **Pattern** | String | Yes | A non-empty JavaScript regular-expression pattern. Defaults to `.*`. |
| **Flags** | String | No | The selected regex flags. The node defaults to `ig`. |
### Flags
| Flag | Setting | Effect |
| ---- | --------------- | -------------------------------------------------------- |
| `g` | **Global** | Finds or replaces every match instead of only the first. |
| `i` | **Ignore case** | Matches letters without case sensitivity. |
| `m` | **Multiline** | Makes `^` and `$` work at line boundaries. |
| `s` | **Dot-all** | Allows `.` to match line-break characters. |
## Outputs
| Output | Type | Description |
| --------- | ------------------ | ---------------------------------------- |
| **Regex** | Regular expression | The compiled pattern and selected flags. |
## Example: invoice IDs
Set **Pattern** to:
```text theme={null}
\bINV-\d{4}\b
```
Keep **Global** on to find every ID and **Ignore case** on if `inv-1042` should
also match. Connect **Regex** to **Extract Text with Regex** to return the
matches.
Enter the pattern without wrapping `/` characters. For example, use `\d+`, not
`/\d+/g`; choose flags separately. An invalid pattern fails when the action
runs.
# Replace Text
Source: https://learn.workflow.dog/reference/actions/text/replace
Replace literal text or regex matches inside a string.
The **Replace Text** action searches a string and substitutes the matching
content. It supports straightforward literal replacement and reusable regular
expressions.
## Inputs
| Input | Type | Required | Description |
| ------------------------- | ------------------ | --------- | --------------------------------------------------------------- |
| **Text** | String | Yes | The text to modify. |
| **Use Regex** | Boolean | Yes | Shows either the literal-text or regex inputs. |
| **Search Text** | String | Sometimes | Literal characters to replace when **Use Regex** is off. |
| **Ignore Case** | Boolean | No | Makes literal matching case-insensitive. Defaults to `false`. |
| **Only First Occurrence** | Boolean | No | Replaces only the first literal match. Defaults to `false`. |
| **Whole Words** | Boolean | No | Limits literal matches to word boundaries. Defaults to `false`. |
| **Search Pattern** | Regular expression | Sometimes | Pattern used when **Use Regex** is on. |
| **Replacement** | String | Yes | Text inserted for each match. Empty text removes matches. |
## Outputs
| Output | Type | Description |
| ------------ | ------ | ------------------------------------- |
| **Replaced** | String | The text after replacements are made. |
## Literal replacement
Literal mode escapes regex punctuation in **Search Text**, so a value such as
`.` matches a period instead of any character. By default, every exact match is
replaced.
For example, replace `draft` with `final` in:
```text theme={null}
draft-report-draft
```
The default result is `final-report-final`. Turn on **Only First Occurrence** to
produce `final-report-draft`.
**Whole Words** uses regex word boundaries. It works best for letters,
numbers, and underscores; punctuation and some non-Latin word boundaries may
behave differently than natural-language word detection.
## Regex replacement
Regex mode uses the flags configured on **Search Pattern**. A regex with the
`g` flag replaces every match; without `g`, only the first match is replaced.
Replacement tokens supported by JavaScript are available, including `$&` for
the complete match and `$1`, `$2`, and so on for capture groups.
For example, use this pattern:
```text theme={null}
(\d{4})-(\d{2})-(\d{2})
```
And this replacement:
```text theme={null}
$2/$3/$1
```
The value `2026-07-24` becomes `07/24/2026`.
Literal-mode options disappear when **Use Regex** is enabled. Configure case
sensitivity, global matching, and boundaries in the **Regular Expression**
action instead.
# Extract Text with Regex
Source: https://learn.workflow.dog/reference/actions/text/search-regex
Find every regex match and return its capture groups.
The **Extract Text with Regex** action searches a string and returns a list of
all matches. Each result contains the complete matched text and a repeatable
list of values captured by parentheses in the pattern.
## Inputs
| Input | Type | Required | Description |
| ------------------ | ------------------ | -------- | --------------------------------- |
| **Text** | String | Yes | The text to search. |
| **Search Pattern** | Regular expression | Yes | The pattern used to find matches. |
## Outputs
| Output | Type | Description |
| ------------------ | --------------- | ----------------------------------------------------- |
| **Matches** | List of objects | Every match, in the order it appears in the text. |
| **Match** | String | The complete text matched by one result. |
| **Capture Groups** | List of strings | The values captured by the pattern's numbered groups. |
The action finds all matches even if the connected regex does not have the
**Global** flag. Its other flags, such as **Ignore case**, **Multiline**, and
**Dot-all**, are preserved.
## Example: extract invoice details
Create a **Regular Expression** with:
```text theme={null}
Invoice\s+(INV-\d+):\s+\$(\d+(?:\.\d{2})?)
```
For `Invoice INV-1042: $75.50`, the first result contains:
* **Match** — `Invoice INV-1042: $75.50`
* First capture group — `INV-1042`
* Second capture group — `75.50`
Connect the entire **Matches** list when a later action can iterate over it, or
expose individual repeat outputs when you expect a fixed number of matches.
If the pattern has no capture groups, each result still has **Match**, while
**Capture Groups** is empty. If nothing matches, **Matches** is an empty list.
# Slice Text
Source: https://learn.workflow.dog/reference/actions/text/slice
Extract part of a string by start and end index.
The **Slice Text** action returns the portion of a string between two indexes.
Indexes are zero-based, and the character at **End** is not included.
## Inputs
| Input | Type | Required | Description |
| --------- | ------ | -------- | ------------------------------------------------------------------ |
| **Text** | String | Yes | The text to extract from. |
| **Start** | Number | No | The first included index. Defaults to `0`. |
| **End** | Number | No | The first excluded index. When omitted, the slice runs to the end. |
## Outputs
| Output | Type | Description |
| --------- | ------ | ------------------------------ |
| **Slice** | String | The extracted portion of text. |
## Index behavior
* Positive indexes count from the beginning, starting at `0`.
* Negative indexes count backward from the end; `-1` refers to the final
character.
* An index outside the string is clamped to its valid bounds.
* If the resolved end comes before the resolved start, the result is empty.
For `workflow`, a start of `0` and end of `4` returns `work`. A start of `-4`
with no end returns `flow`.
# Split Text
Source: https://learn.workflow.dog/reference/actions/text/split
Break a string into a list using literal text or a regex separator.
The **Split Text** action divides a string wherever a separator occurs and
returns the pieces in order. Choose between a literal separator and a reusable
regular expression.
## Inputs
| Input | Type | Required | Description |
| --------------------- | ------------------ | --------- | ----------------------------------------------- |
| **Text** | String | Yes | The text to split. |
| **Use Regex** | Boolean | Yes | Shows the literal or regex separator input. |
| **Separator Text** | String | Sometimes | Exact separator used when **Use Regex** is off. |
| **Separator Pattern** | Regular expression | Sometimes | Pattern used when **Use Regex** is on. |
## Outputs
| Output | Type | Description |
| --------- | --------------- | ------------------------------------------------------ |
| **Split** | List of strings | The text pieces before, between, and after separators. |
## Examples
Split `red,green,blue` with a **Separator Text** of `,` to return:
```json theme={null}
["red", "green", "blue"]
```
Connect **Line Break** as the separator to split text into lines.
Split `red, green; blue` with a pattern of `\s*[,;]\s*` to accept either
punctuation mark and discard nearby spaces:
```json theme={null}
["red", "green", "blue"]
```
A separator at the beginning or end produces an empty first or last item.
Adjacent separators produce empty items between them.
Capturing parentheses in a regex separator add the captured separator text to
the output list. Use non-capturing groups such as `(?:,|;)` when those values
should not become list items.
# Starts With
Source: https://learn.workflow.dog/reference/actions/text/starts-with
Check whether text begins with a specific sequence of characters.
The **Starts With** action returns whether a string begins with an exact prefix.
Use it to recognize reference formats, URL schemes, commands, or other fixed
openings.
## Inputs
| Input | Type | Required | Description |
| --------------- | ------- | -------- | ---------------------------------------------------------------- |
| **Text** | String | Yes | The text to check. |
| **Search** | String | Yes | The prefix expected at the beginning of the text. |
| **Ignore Case** | Boolean | No | Compares lowercase versions of both values. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ---------- | ------- | --------------------------------------------------------------- |
| **Result** | Boolean | `true` when **Text** starts with **Search**; otherwise `false`. |
## Example
With **Text** set to `INV-1042` and **Search** set to `INV-`, the action returns
`true`.
Leading spaces and line breaks count. Use **Trim Whitespace** first if the
prefix should be checked after surrounding whitespace is removed.
# Title Case
Source: https://learn.workflow.dog/reference/actions/text/titlecase
Turn words and identifiers into start-cased text.
The **Title Case** action converts text to start case. It separates common word
boundaries—including spaces, punctuation, camel case, and underscores—then
capitalizes each resulting word.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | -------------------- |
| **Text** | String | Yes | The text to convert. |
## Outputs
| Output | Type | Description |
| -------- | ------ | ------------------------------------- |
| **text** | String | The start-cased version of the input. |
## Examples
| Input | Output |
| ---------------- | ----------------- |
| `customer_name` | `Customer Name` |
| `billingAddress` | `Billing Address` |
| `MONTHLY-report` | `MONTHLY Report` |
This is identifier-friendly start casing, not a grammar-aware publishing
style. It does not apply rules for articles, prepositions, or brand names.
# Convert to Text
Source: https://learn.workflow.dog/reference/actions/text/to-string
Coerce a workflow value into text.
The **Convert to Text** action turns an incoming value into a string. Use it
when a later action requires text but the current value is a number, boolean,
or another coercible type.
## Inputs
| Input | Type | Required | Description |
| --------- | ---- | -------- | --------------------- |
| **Value** | Any | Yes | The value to convert. |
## Outputs
| Output | Type | Description |
| -------- | ------ | ------------------------- |
| **Text** | String | The coerced string value. |
Common primitive conversions include `42` → `"42"` and `true` → `"true"`.
Conversion is not JSON serialization. Complex values may not produce the
structured text you expect; serialize them explicitly when the exact format
matters.
# Trim Whitespace
Source: https://learn.workflow.dog/reference/actions/text/trim
Remove whitespace from both ends of a string.
The **Trim Whitespace** action removes leading and trailing whitespace while
leaving whitespace inside the text unchanged.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ----------------- |
| **Text** | String | Yes | The text to trim. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------------------ |
| **Trimmed** | String | The text without leading or trailing whitespace. |
Spaces, tabs, and line breaks at either end are removed. To reduce repeated
whitespace within the text, use **Collapse Whitespace**.
# Uppercase
Source: https://learn.workflow.dog/reference/actions/text/uppercase
Convert every letter in a string to uppercase.
The **Uppercase** action converts text with JavaScript's standard uppercase
rules. Non-letter characters remain unchanged.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | -------------------- |
| **Text** | String | Yes | The text to convert. |
## Outputs
| Output | Type | Description |
| -------- | ------ | -------------------------------------- |
| **TEXT** | String | The input text converted to uppercase. |
For example, `Invoice #a19` becomes `INVOICE #A19`.
# Cancel Booking
Source: https://learn.workflow.dog/reference/actions/tidycal/cancel-booking
Cancel a TidyCal booking by ID.
**Cancel Booking** marks an existing TidyCal booking as cancelled.
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ------------------------------------------------ |
| **Third-party account** | TidyCal account | Yes | The account containing the booking. |
| **Booking ID** | Positive integer | Yes | The booking to cancel. |
| **Reason** | String | No | An optional cancellation reason sent to TidyCal. |
The action has no output.
# Create Booking
Source: https://learn.workflow.dog/reference/actions/tidycal/create-booking
Book a TidyCal timeslot for a contact.
**Create Booking** creates an appointment for a TidyCal booking type.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | --------------------------------------------------------------------------- |
| **Third-party account** | TidyCal account | Yes | The account that owns the booking type. |
| **Booking Type** | String or number | Yes | A booking type ID such as `418343` or URL slug such as `15-minute-meeting`. |
| **Start Time** | Date | Yes | When the appointment begins. |
| **Name** | String | Yes | The person making the booking. |
| **Email** | Email | Yes | The person's email address. |
| **Timezone** | String | Yes | The timezone used for the booking. |
## Output
| Output | Type | Description |
| -------------- | ------ | ----------------------------------------- |
| **Booking ID** | Number | TidyCal's identifier for the new booking. |
Check availability before creating the booking. This action fails when the
booking type cannot be found or TidyCal rejects the requested time.
# Get Booking
Source: https://learn.workflow.dog/reference/actions/tidycal/get-booking
Retrieve complete details for a TidyCal booking.
**Get Booking** fetches one TidyCal booking by its ID.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ----------------------------------- |
| **Third-party account** | TidyCal account | Yes | The account containing the booking. |
| **Booking ID** | Positive integer | Yes | The booking to retrieve. |
## Outputs
The action returns **Booking ID**, **Booking Type**, **Starts At**, **Ends At**,
**Timezone**, **Meeting URL**, **Contact ID**, **Contact Name**, **Contact
Email**, **Created At**, and **Cancelled At**.
**Questions** is a list of `{ question, answer }` objects containing the
custom booking-form responses.
**Cancelled At** and **Meeting URL** can be empty when they do not apply.
# List Available Timeslots
Source: https://learn.workflow.dog/reference/actions/tidycal/list-available-timeslots
Find open times for a TidyCal booking type.
**List Available Timeslots** returns open intervals for a booking type within a
date range.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | ---------------- | -------- | ----------------------------------------------------------------- |
| **Third-party account** | TidyCal account | Yes | The account that owns the booking type. |
| **Booking Type** | String or number | Yes | The booking type ID or URL slug. |
| **Starts After** | Date | No | The beginning of the search window. Defaults to the current time. |
| **Ends Before** | Date | Yes | The end of the search window. |
## Output
**Timeslots** is a list of objects with:
* **Start Time**
* **End Time**
* **Available Slots** — Remaining capacity, including group-booking capacity.
**Ends Before** must be later than **Starts After**. The action fails when the
range is reversed or the booking type does not exist.
# List Bookings
Source: https://learn.workflow.dog/reference/actions/tidycal/list-bookings
List TidyCal bookings with optional date filters.
**List Bookings** retrieves bookings from a TidyCal account, optionally limited
to a time window.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------ |
| **Third-party account** | TidyCal account | Yes | The account to inspect. |
| **Starts After** | Date | No | Include bookings starting on or after this time. |
| **Ends Before** | Date | No | Include bookings ending before this time. |
## Output
**Bookings** is a list. Each item includes booking ID and type, start and end
times, timezone, meeting URL, contact details, creation and cancellation
timestamps, and a list of custom question/answer pairs.
Leave both dates empty to retrieve the account's available booking history, or
set a narrow range before processing every booking downstream.
# Add Attachment
Source: https://learn.workflow.dog/reference/actions/trello/add-attachment
Attach a public URL to a Trello card.
**Add Attachment** adds a URL attachment to a Trello card and can use it as the
card cover.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | --------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Attachment URL** | URL | Yes | The public URL to attach. |
| **Name** | String | No | An optional attachment display name. |
| **Set Cover** | Boolean | No | Use the attachment as the cover. Default off. |
## Outputs
| Output | Type | Description |
| ----------------- | ------ | ------------------------------------------- |
| **Attachment** | Object | The created attachment's normalized fields. |
| **Attachment ID** | String | Trello's identifier for the attachment. |
**Attachment** exposes **ID**, **Name**, **URL**, **Bytes**, **Added At**,
**MIME Type**, **Is Upload**, and **Position**. Some metadata may be empty for
URL attachments.
# Add Checklist Item
Source: https://learn.workflow.dog/reference/actions/trello/add-checklist-item
Add an item to a Trello checklist.
**Add Checklist Item** creates a task within an existing Trello checklist.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------------------------ |
| **Third-party account** | Trello account | Yes | An account with write access to the checklist. |
| **Checklist ID** | String | Yes | The destination Trello checklist. |
| **Name** | String | Yes | The checklist item name. |
| **Position** | Choice | No | Put it at the `top` or `bottom`. Defaults to `bottom`. |
| **Completed** | Boolean | No | Create the item as complete. Defaults to off. |
| **Due** | Date | No | The checklist item due date. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ----------------------------------------------- |
| **Item** | Object | The created checklist item's normalized fields. |
| **Item ID** | String | Trello's identifier for the item. |
**Item** exposes **ID**, **Checklist ID**, **Name**, **State**, **Completed**,
**Position**, **Due**, and **Member ID**.
# Add Comment
Source: https://learn.workflow.dog/reference/actions/trello/add-comment
Add a comment to a Trello card.
**Add Comment** posts a non-empty text comment to a Trello card.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Text** | String | Yes | The comment text. |
## Outputs
| Output | Type | Description |
| -------------- | ------ | ---------------------------------------- |
| **Comment** | Object | The created comment's normalized fields. |
| **Comment ID** | String | Trello's action ID for the comment. |
**Comment** exposes **ID**, **Text**, **Commented At**, **Creator Name**, and
**Creator Username**.
# Add Labels
Source: https://learn.workflow.dog/reference/actions/trello/add-labels
Add existing labels to a Trello card.
**Add Labels** adds one or more labels without changing the card's other
labels.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ---------------------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Labels** | List of strings | Yes | Label IDs, names, or colors. Matching is case-insensitive. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------ |
| **Card** | Object | The card after its labels are added. |
| **Card ID** | String | The updated card's ID. |
Label IDs take precedence over names, and names take precedence over colors.
Duplicate references are applied only once.
A color or name that matches multiple labels is ambiguous. Use a label ID to
identify the intended label.
# Add Members
Source: https://learn.workflow.dog/reference/actions/trello/add-members
Assign board members to a Trello card.
**Add Members** assigns one or more members without replacing the card's
current members.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Members** | List of strings | Yes | Member IDs, usernames, or full names. Matching is case-insensitive. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ---------------------------------------- |
| **Card** | Object | The card after the members are assigned. |
| **Card ID** | String | The updated card's ID. |
Member IDs take precedence over usernames, and usernames take precedence over
full names.
A full name shared by multiple board members is ambiguous. Use a member ID or
unique username instead.
# Create Card
Source: https://learn.workflow.dog/reference/actions/trello/create-card
Create a card in a Trello list.
**Create Card** adds a card to a Trello list and can assign labels, members,
dates, and an initial position.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------------ |
| **Third-party account** | Trello account | Yes | An account with write access to the board. |
| **List ID** | String | Yes | The destination Trello list. |
| **Name** | String | Yes | The card name. |
| **Description** | String | No | The card description. |
| **Labels** | List of strings | No | Label IDs, names, or colors. Matching is case-insensitive. |
| **Members** | List of strings | No | Member IDs, usernames, or full names. Matching ignores case. |
| **Position** | Choice | No | Put the card at the `top` or `bottom`. Defaults to `bottom`. |
| **Due** | Date | No | The card due date. |
| **Start** | Date | No | The card start date. |
| **Due Complete** | Boolean | No | Whether the due date is complete. Defaults to off. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------------- |
| **Card** | Object | The created card and its normalized fields. |
| **Card ID** | String | Trello's identifier for the created card. |
**Card** exposes the card's name, description, archived state, board and list
IDs, URLs, position, dates, member IDs, label IDs, and last activity time.
Label colors and full member names can be ambiguous. Use IDs when more than
one board label or member could match.
# Create Checklist
Source: https://learn.workflow.dog/reference/actions/trello/create-checklist
Create a checklist on a Trello card.
**Create Checklist** adds an empty checklist to a Trello card.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------------------------ |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Name** | String | Yes | The checklist name. |
| **Position** | Choice | No | Put it at the `top` or `bottom`. Defaults to `bottom`. |
## Outputs
| Output | Type | Description |
| ---------------- | ------ | ------------------------------------------ |
| **Checklist** | Object | The created checklist's normalized fields. |
| **Checklist ID** | String | Trello's identifier for the checklist. |
**Checklist** exposes **ID**, **Card ID**, **Board ID**, **Name**, **Position**,
**Items**, **Item Count**, and **Completed Item Count**.
# Delete Attachment
Source: https://learn.workflow.dog/reference/actions/trello/delete-attachment
Permanently remove an attachment from a Trello card.
**Delete Attachment** permanently removes one attachment from a Trello card.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Attachment ID** | String | Yes | The attachment to delete. |
## Output
| Output | Type | Description |
| ----------------- | ------ | -------------------------- |
| **Attachment ID** | String | The deleted attachment ID. |
Deleting an attachment cannot be undone by this action.
# Delete Checklist
Source: https://learn.workflow.dog/reference/actions/trello/delete-checklist
Permanently delete a Trello checklist.
**Delete Checklist** permanently removes a checklist and its items from Trello.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ---------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the checklist. |
| **Checklist ID** | String | Yes | The Trello checklist to delete. |
The action has no output. Continue the workflow after Trello confirms the
checklist was deleted.
Deleting a checklist also removes its checklist items and cannot be undone by
this action.
# Delete Checklist Item
Source: https://learn.workflow.dog/reference/actions/trello/delete-checklist-item
Permanently delete an item from a Trello checklist.
**Delete Checklist Item** permanently removes one item from a Trello checklist.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ---------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the checklist. |
| **Checklist ID** | String | Yes | The checklist that contains the item. |
| **Item ID** | String | Yes | The Trello checklist item to delete. |
The action has no output. Continue the workflow after Trello confirms the item
was deleted.
Deleting a checklist item cannot be undone by this action.
# Get Card
Source: https://learn.workflow.dog/reference/actions/trello/get-card
Get a Trello card by ID, short link, or URL.
**Get Card** retrieves one Trello card using any common Trello card reference.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------------ |
| **Card** | Object | The card and its normalized fields. |
| **Card ID** | String | Trello's identifier for the returned card. |
The card object exposes **ID**, **Name**, **Description**, **Closed**, **Board
ID**, **List ID**, **URL**, **Short URL**, **Position**, **Due**, **Start**,
**Due Complete**, **Member IDs**, **Label IDs**, and **Last Activity At**.
# Get List Cards
Source: https://learn.workflow.dog/reference/actions/trello/get-list-cards
Get cards from a Trello list.
**Get List Cards** retrieves cards currently associated with one Trello list.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ----------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with access to the list. |
| **List ID** | String | Yes | The Trello list to inspect. |
| **Filter** | Choice | No | `open`, `closed`, or `all`. Defaults to `open`. |
## Outputs
| Output | Type | Description |
| --------- | --------------- | ----------------------------- |
| **Cards** | List of objects | Cards in the selected list. |
| **Count** | Number | The number of cards returned. |
Each card includes its IDs, name, description, archived state, URLs, position,
dates, members, labels, and last activity time.
# List Attachments
Source: https://learn.workflow.dog/reference/actions/trello/list-attachments
List attachments on a Trello card.
**List Attachments** retrieves every attachment associated with one Trello
card.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
## Outputs
| Output | Type | Description |
| --------------- | --------------- | ----------------------------------- |
| **Attachments** | List of objects | Attachments on the card. |
| **Count** | Number | The number of attachments returned. |
Each attachment exposes **ID**, **Name**, **URL**, **Bytes**, **Added At**,
**MIME Type**, **Is Upload**, and **Position**.
# List Board Lists
Source: https://learn.workflow.dog/reference/actions/trello/list-board-lists
List the columns on a Trello board.
**List Board Lists** retrieves the lists, or columns, on one Trello board.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ----------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with access to the board. |
| **Board ID** | String | Yes | The board whose lists should be returned. |
| **Filter** | Choice | No | `open`, `closed`, or `all`. Defaults to `open`. |
## Outputs
| Output | Type | Description |
| --------- | --------------- | ----------------------------- |
| **Lists** | List of objects | Lists on the selected board. |
| **Count** | Number | The number of lists returned. |
Each list exposes **ID**, **Name**, **Closed**, **Board ID**, and **Position**.
Pass a list ID to **Create Card** or **Get List Cards**.
# List Board Members
Source: https://learn.workflow.dog/reference/actions/trello/list-board-members
List members of a Trello board.
**List Board Members** retrieves the people who belong to one Trello board.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------ |
| **Third-party account** | Trello account | Yes | An account with access to the board. |
| **Board ID** | String | Yes | The board whose members are listed. |
## Outputs
| Output | Type | Description |
| ----------- | --------------- | ------------------------------- |
| **Members** | List of objects | Members of the selected board. |
| **Count** | Number | The number of members returned. |
Each member exposes **ID**, **Full Name**, and **Username**.
Member IDs are the safest values to pass to card actions when two people have
the same full name.
# List Boards
Source: https://learn.workflow.dog/reference/actions/trello/list-boards
List Trello boards available to the connected account.
**List Boards** retrieves boards that the connected Trello account can access.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ----------------------------------------------- |
| **Third-party account** | Trello account | Yes | The account whose boards are listed. |
| **Filter** | Choice | No | `open`, `closed`, or `all`. Defaults to `open`. |
## Outputs
| Output | Type | Description |
| ---------- | --------------- | -------------------------------- |
| **Boards** | List of objects | The boards available to account. |
| **Count** | Number | The number of boards returned. |
Each board exposes **ID**, **Name**, **Description**, **Closed**, **URL**,
**Short URL**, and **Last Activity At**.
Use the returned board ID with **List Board Lists**, **List Board Members**,
or a Trello card trigger.
# List Card Checklists
Source: https://learn.workflow.dog/reference/actions/trello/list-card-checklists
List checklists and their items on a Trello card.
**List Card Checklists** retrieves every checklist on one card, including its
checklist items.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
## Outputs
| Output | Type | Description |
| -------------- | --------------- | ---------------------------------- |
| **Checklists** | List of objects | Checklists on the card. |
| **Count** | Number | The number of checklists returned. |
Each checklist exposes **ID**, **Card ID**, **Board ID**, **Name**, **Position**,
**Items**, **Item Count**, and **Completed Item Count**. Each item contains its
ID, checklist ID, name, state, completion status, position, due date, and
assigned member ID.
# List Comments
Source: https://learn.workflow.dog/reference/actions/trello/list-comments
List comments on a Trello card.
**List Comments** retrieves recent comment actions from one Trello card.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------------------ |
| **Third-party account** | Trello account | Yes | An account with access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Limit** | Number | No | Comments to return, from 1 to 1000. Default 100. |
## Outputs
| Output | Type | Description |
| ------------ | --------------- | -------------------------------- |
| **Comments** | List of objects | The returned card comments. |
| **Count** | Number | The number of comments returned. |
Each comment exposes **ID**, **Text**, **Commented At**, **Creator Name**, and
**Creator Username**. Creator details can be empty when Trello omits them.
# Remove Labels
Source: https://learn.workflow.dog/reference/actions/trello/remove-labels
Remove selected labels from a Trello card.
**Remove Labels** removes one or more labels without changing the card's other
labels.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ---------------------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Labels** | List of strings | Yes | Label IDs, names, or colors. Matching is case-insensitive. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | -------------------------------------- |
| **Card** | Object | The card after its labels are removed. |
| **Card ID** | String | The updated card's ID. |
Use **Update Card** with an empty **Labels** list when every label should be
removed.
# Remove Members
Source: https://learn.workflow.dog/reference/actions/trello/remove-members
Unassign selected members from a Trello card.
**Remove Members** unassigns one or more members without changing the card's
other members.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Members** | List of strings | Yes | Member IDs, usernames, or full names. Matching is case-insensitive. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------------ |
| **Card** | Object | The card after the members are unassigned. |
| **Card ID** | String | The updated card's ID. |
Use **Update Card** with an empty **Members** list when every member should be
removed.
# Search Cards
Source: https://learn.workflow.dog/reference/actions/trello/search-cards
Search Trello cards by text.
**Search Cards** searches accessible Trello cards by text and can restrict the
search to one board.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | ------------------------------------------------------ |
| **Third-party account** | Trello account | Yes | The account used to search Trello. |
| **Query** | String | Yes | Non-empty search text. |
| **Board ID** | String | No | Restrict results to one board. |
| **Limit** | Number | No | Cards per page, from 1 to 1000. Defaults to 50. |
| **Page** | Number | No | Zero-based results page, from 0 to 100. Defaults to 0. |
| **Partial** | Boolean | No | Match partial words. Defaults to off. |
## Outputs
| Output | Type | Description |
| --------- | --------------- | --------------------------------- |
| **Cards** | List of objects | Cards matching the search. |
| **Count** | Number | The number of cards on this page. |
Increase **Page** to retrieve later results. **Count** describes only the
returned page, not every possible match.
# Update Card
Source: https://learn.workflow.dog/reference/actions/trello/update-card
Edit, move, complete, archive, or reopen a Trello card.
**Update Card** changes one or more fields on an existing Trello card.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | --------------- | -------- | ------------------------------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | A card ID, short link, or complete card URL. |
| **Name** | String | No | A new card name. |
| **Description** | String | No | A new card description. |
| **Labels** | List of strings | No | Replacement label IDs, names, or colors; an empty list removes all. |
| **Members** | List of strings | No | Replacement member IDs, usernames, or names; empty removes all. |
| **List ID** | String | No | Move the card to this list. |
| **Closed** | Boolean | No | Archive the card when on, or reopen it when off. |
| **Position** | Choice | No | Move the card to the `top` or `bottom` of its list. |
| **Due** | Date | No | Set a new due date. |
| **Clear Due Date** | Boolean | No | Remove the due date. |
| **Start** | Date | No | Set a new start date. |
| **Clear Start Date** | Boolean | No | Remove the start date. |
| **Due Complete** | Boolean | No | Set whether the due date is complete. |
Provide at least one field to update. **Due** cannot be combined with **Clear
Due Date**, and **Start** cannot be combined with **Clear Start Date**.
## Outputs
| Output | Type | Description |
| ----------- | ------ | ----------------------------------------- |
| **Card** | Object | The card after Trello applies the update. |
| **Card ID** | String | The updated card's ID. |
**Labels** and **Members** replace the complete existing sets. Use **Add
Labels**, **Remove Labels**, **Add Members**, or **Remove Members** to make an
incremental change.
# Update Checklist Item
Source: https://learn.workflow.dog/reference/actions/trello/update-checklist-item
Edit a Trello checklist item.
**Update Checklist Item** renames, completes, reschedules, or repositions an
item in a Trello checklist.
## Inputs
| Input | Type | Required | Description |
| ----------------------- | -------------- | -------- | -------------------------------------------------- |
| **Third-party account** | Trello account | Yes | An account with write access to the card. |
| **Card ID or URL** | String | Yes | The parent card's ID, short link, or complete URL. |
| **Item ID** | String | Yes | The Trello checklist item to update. |
| **Name** | String | No | A new item name. |
| **State** | Choice | No | Mark the item `complete` or `incomplete`. |
| **Position** | Choice | No | Move the item to the `top` or `bottom`. |
| **Due** | Date | No | A new item due date. |
Provide at least one field to update.
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------ |
| **Item** | Object | The checklist item after the update. |
| **Item ID** | String | The updated checklist item ID. |
The item object includes its checklist ID, name, state, completion status,
position, due date, and assigned member ID.
# Build URL
Source: https://learn.workflow.dog/reference/actions/utilities/build-url
Construct an absolute URL from a base, path, query parameters, and fragment.
The **Build URL** action assembles and safely serializes a URL. It resolves an
optional path against the base URL, sets query parameters, and adds a fragment.
## Inputs
| Input | Type | Required | Description |
| -------------------- | ----------------- | --------- | ------------------------------------------------------ |
| **Base URL** | String | Yes | A valid absolute base URL. |
| **Path** | String | No | A relative or absolute path resolved against the base. |
| **Query Parameters** | Key/value entries | No | Parameter names and string values to set. |
| **Name** | String | Per entry | The query-parameter name. |
| **Value** | String | Per entry | The query-parameter value. |
| **Fragment** | String | No | The hash fragment, with or without a leading `#`. |
## Outputs
| Output | Type | Description |
| ------- | ------ | ---------------------------- |
| **URL** | String | The complete serialized URL. |
## Example
Configure:
| Setting | Value |
| --------------- | ----------------------------- |
| **Base URL** | `https://api.example.com/v1/` |
| **Path** | `customers/42` |
| Query `include` | `orders` |
| **Fragment** | `details` |
The result is:
```text theme={null}
https://api.example.com/v1/customers/42?include=orders#details
```
Parameter names and values are percent-encoded automatically. A parameter set
here replaces an existing base-URL parameter with the same name.
URL path resolution follows browser rules. A relative path preserves the last
base segment only when the base path ends in `/`; a path beginning with `/`
replaces the base path from the host root.
# Decode URI Component
Source: https://learn.workflow.dog/reference/actions/utilities/decode-uri-component
Convert percent-encoded URL text back to readable text.
The **Decode URI Component** action reverses percent encoding for one URL
component.
## Inputs
| Input | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------- |
| **Encoded** | String | Yes | The percent-encoded text. |
## Outputs
| Output | Type | Description |
| -------- | ------ | ----------------- |
| **Text** | String | The decoded text. |
For example, `quarterly%20report%20%26%20notes` becomes
`quarterly report & notes`.
A `+` remains a plus sign. This action does not apply HTML form-query rules
that sometimes interpret `+` as a space.
Invalid or incomplete percent escapes, such as `%E0%A4%A`, cause the action to
fail.
# Delay
Source: https://learn.workflow.dog/reference/actions/utilities/delay
Pause the current workflow for up to five seconds.
The **Delay** action waits for a duration before the next connected action can
run. Use it for short pacing intervals—not long-term scheduling.
## Inputs
| Input | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------------------------------------ |
| **Duration** | Number | Yes | Seconds to wait, from `0` through `5`. The runtime default is `1`. |
This action has no data outputs. Workflow execution continues after the wait
finishes.
Decimal durations are supported; `0.5` waits for approximately half a second.
Actual timing may be slightly longer under load.
Values below `0` or above `5` are rejected. Use a schedule or another
purpose-built waiting mechanism for delays longer than five seconds.
# Encode URI Component
Source: https://learn.workflow.dog/reference/actions/utilities/encode-uri-component
Percent-encode text for use as one part of a URL.
The **Encode URI Component** action escapes text so it can safely occupy a
single URL component, such as a query value, path segment, or fragment value.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ------------------- |
| **Text** | String | Yes | The text to encode. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------- |
| **Encoded** | String | The percent-encoded text. |
For example:
```text theme={null}
quarterly report & notes
```
becomes:
```text theme={null}
quarterly%20report%20%26%20notes
```
This encodes one component, not a complete URL. Use **Build URL** when
constructing a URL from several parts.
# Encode URI Parameters
Source: https://learn.workflow.dog/reference/actions/utilities/encode-uri-params
Turn parameter entries into a URL query string.
The **Encode URI Parameters** action serializes key/value entries into query
string format without adding the leading `?`.
## Inputs
| Input | Type | Required | Description |
| -------------- | ----------------- | --------- | ---------------------------------- |
| **Parameters** | Key/value entries | No | The query parameters to serialize. |
| **Name** | String | Per entry | The parameter name. |
| **Value** | String | Per entry | The parameter value. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | --------------------------------------- |
| **Encoded** | String | The query string without a leading `?`. |
For `search = red shoes` and `page = 2`, the result is:
```text theme={null}
search=red+shoes&page=2
```
Names and values are encoded with standard URL query rules. Empty parameter
sets produce empty text.
Parameter entries form an object, so each name can occur only once. Use a
different approach when an API requires repeated keys such as `tag=a&tag=b`.
# Escape HTML
Source: https://learn.workflow.dog/reference/actions/utilities/escape-html
Replace HTML-sensitive characters with safe entities.
The **Escape HTML** action converts characters that could be interpreted as
markup into HTML entities. Use it when inserting plain user-supplied text into
an HTML string.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | ------------------------- |
| **Text** | String | Yes | The plain text to escape. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | -------------------------------------- |
| **Escaped** | String | The text with HTML characters escaped. |
For example:
```html theme={null}
Hello
```
becomes:
```html theme={null}
<strong title="A & B">Hello</strong>
```
The action escapes `&`, `<`, `>`, double quotes, and single quotes. It does not
sanitize or validate an existing HTML document.
# Execute Code
Source: https://learn.workflow.dog/reference/actions/utilities/execute-code
Run custom JavaScript or TypeScript with Bun and return named exports.
The **Execute Code** action runs a JavaScript or TypeScript module in a
temporary Bun container. Use it when a workflow needs a transformation that
available actions cannot express.
Custom code can make network requests, import packages, consume resources, and
expose any values connected as inputs. Review the code and every input before
running it, especially credentials or personal data.
## Inputs
| Input | Type | Required | Description |
| ------------------------------ | ------------------------ | --------- | ----------------------------------------------------------------------- |
| **Code** | String | Yes | The module source to execute. |
| **Language** | JavaScript or TypeScript | Yes | The source language. Defaults to **TypeScript**. |
| **Input Variables** | Key/value entries | No | JSON-serializable values exposed to the module. |
| **Name** | String | Per entry | The property name in the input object. |
| **Value** | JSON value | Per entry | The value available under that name. |
| **Include Timestamps In Logs** | Boolean | No | Prefixes captured log lines with local timestamps. Defaults to `false`. |
## Outputs
| Output | Type | Description |
| ----------- | ------ | ------------------------------------------------------------ |
| **Outputs** | Object | The JSON-serializable named exports from the module. |
| **Logs** | String | Captured standard output and standard error, joined as text. |
You can expose properties from **Outputs** as individual node outputs, then
connect only the values later actions need.
## Read inputs and return outputs
Import the default export from `./inputs`, then export each result as a named
value:
```ts theme={null}
import inputs from "./inputs"
const subtotal = Number(inputs.subtotal)
const taxRate = Number(inputs.taxRate)
export const tax = subtotal * taxRate
export const total = subtotal + tax
console.log(`Calculated total for ${subtotal}`)
```
Configure **Input Variables** with `subtotal` and `taxRate`. The action returns:
```json theme={null}
{
"tax": 8,
"total": 108
}
```
The message written with `console.log` appears in **Logs**, not **Outputs**.
Use identifier-like input names such as `customerId` or `lineItems`. They are
easier to access as `inputs.customerId` and produce useful TypeScript editor
hints.
## Import packages
Code runs with the Bun runtime, so standard imports are supported:
```ts theme={null}
import inputs from "./inputs"
import { groupBy } from "lodash-es"
export const grouped = groupBy(inputs.orders, "status")
```
Bun can resolve npm package imports during execution. Version specifiers may be
used when the exact package version matters.
## Serialization rules
Inputs and outputs cross the action boundary as JSON:
* Inputs may contain strings, numbers, booleans, `null`, lists, and objects.
* Exported functions, symbols, `undefined`, and other non-JSON values are not
reliable outputs.
* `BigInt`, circular objects, and other values that JSON cannot serialize cause
the run to fail.
* Class instances lose behavior when serialized; return plain data instead.
The code is executed as a module. Only exported values are returned. Local
variables stay private unless you add a named export.
## Troubleshooting
Confirm that its **Input Variables** name matches the property read from the
default `./inputs` export. Names are case-sensitive.
Add named exports such as `export const result = value`. Logging a value does
not return it.
Check every exported value for JSON compatibility. Remove functions, `BigInt`,
circular references, and unsupported runtime objects.
Check the package name and import path. If reproducibility matters, specify
a supported npm version in the import rather than relying on the latest
resolved package.
# HTML to Markdown
Source: https://learn.workflow.dog/reference/actions/utilities/html-to-md
Convert HTML markup into Markdown text.
The **HTML to Markdown** action converts an HTML string into a Markdown
representation. Use it to make web or email content easier to store, summarize,
or send through text-oriented actions.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | --------------------------- |
| **HTML** | String | Yes | The HTML markup to convert. |
## Outputs
| Output | Type | Description |
| ------------ | ------ | ---------------------------- |
| **Markdown** | String | The converted Markdown text. |
For example:
```html theme={null}
Status
The build is ready.
- Tests passed
- Review complete
```
becomes Markdown similar to:
```markdown theme={null}
## Status
The build is **ready**.
- Tests passed
- Review complete
```
HTML and Markdown do not have identical feature sets. Complex tables, custom
elements, inline styles, and layout markup may be simplified or omitted.
# HTML to Text
Source: https://learn.workflow.dog/reference/actions/utilities/html-to-text
Convert HTML markup into readable plain text.
The **HTML to Text** action removes markup while preserving readable structure
for headings, paragraphs, lists, and links. Use it before keyword matching,
plain-text notifications, or AI prompts that do not need HTML.
## Inputs
| Input | Type | Required | Description |
| -------- | ------ | -------- | --------------------------- |
| **HTML** | String | Yes | The HTML markup to convert. |
## Outputs
| Output | Type | Description |
| -------- | ------ | ------------------------- |
| **Text** | String | The converted plain text. |
For example:
```html theme={null}
Hello Ada.
Your order is ready.
```
produces readable text with the two paragraph contents and no `` or
`` tags.
This is a content conversion, not an HTML sanitizer. The output is plain text,
but conversion choices such as line wrapping and link rendering follow the
action's built-in defaults.
# Markdown to HTML
Source: https://learn.workflow.dog/reference/actions/utilities/markdown-to-html
Render Markdown text as HTML.
The **Markdown to HTML** action renders headings, emphasis, links, lists, code
blocks, and other supported Markdown syntax into an HTML string.
## Inputs
| Input | Type | Required | Description |
| ------------ | ------ | -------- | ---------------------------- |
| **Markdown** | String | Yes | The Markdown text to render. |
## Outputs
| Output | Type | Description |
| -------- | ------ | ------------------------- |
| **HTML** | String | The rendered HTML markup. |
For example:
```markdown theme={null}
## Status
The build is **ready**.
```
renders approximately:
```html theme={null}
Status
The build is ready.
```
The generated HTML is not sanitized. Markdown can contain raw HTML, links, and
other content that is unsafe to render in a trusted page or email without a
separate sanitization policy.
# Resolve Account Secret
Source: https://learn.workflow.dog/reference/actions/utilities/resolve-account-secret
Expose the credential data stored in a connected third-party account.
The **Resolve Account Secret** action returns the raw secret object behind a
third-party account. It is intended for advanced integrations whose generic
HTTP or code step must use credentials that no dedicated action supports.
This action exposes credentials in plain text to the workflow graph and run
data. Use it only when no safer account-aware action is available. Never send
the output to logs, messages, analytics, or untrusted services.
## Inputs
| Input | Type | Required | Description |
| ----------- | ------------------- | -------- | ------------------------------------------- |
| **Account** | Third-party account | Yes | The connected account whose secret is read. |
## Outputs
| Output | Type | Description |
| ---------- | ------ | ------------------------------------ |
| **Secret** | Object | The account's raw credential fields. |
The available fields depend on the account type. An API-key account may expose
a key, while an OAuth account may include access or refresh tokens.
## Handle the output safely
* Connect only the specific secret field required by the next trusted action.
* Do not copy secrets into static node configuration.
* Do not include the secret in **Execute Code** logs or error messages.
* Remove this action after replacing a custom integration with a dedicated
account-aware action.
Resolving a secret does not refresh, rotate, or validate the credential. It
returns the value currently stored for the selected account.
# Validate JSON Schema
Source: https://learn.workflow.dog/reference/actions/utilities/validate-json-schema
Validate any value against JSON Schema and expose validation results.
The **Validate JSON Schema** action checks workflow data against a JSON Schema.
It returns a boolean and every validation error. For object schemas, it also
creates outputs for the schema's top-level properties.
## Inputs
| Input | Type | Required | Description |
| ---------- | ------ | -------- | --------------------------- |
| **Data** | Any | Yes | The value to validate. |
| **Schema** | String | Yes | A JSON-encoded JSON Schema. |
## Outputs
| Output | Type | When shown | Description |
| ------------- | --------------- | ----------------------------- | ---------------------------------------------- |
| **Is Valid** | Boolean | Always | Whether **Data** satisfies the schema. |
| **Errors** | List of strings | Always | All validation errors; empty when valid. |
| **Validated** | Varies | Non-object schemas | The original data value after validation. |
| Property name | Varies | Object schema with properties | The original value of that top-level property. |
The schema editor uses top-level `type` and `properties` to configure the
additional outputs. String, number, integer, boolean, and object properties
receive matching workflow types; arrays and unknown schema types remain
untyped.
## Example: validate a customer
Use this schema:
```json theme={null}
{
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1 },
"age": { "type": "integer", "minimum": 18 },
"active": { "type": "boolean" }
},
"required": ["name", "age"],
"additionalProperties": false
}
```
The node exposes `name`, `age`, and `active` as outputs. For:
```json theme={null}
{
"name": "Ada",
"age": 17,
"active": true
}
```
**Is Valid** is `false`, and **Errors** includes an entry similar to:
```text theme={null}
/age: must be >= 18
```
The property outputs still expose the supplied values, even when validation
fails. Use **Is Valid** to guard any branch that consumes them.
Validation does not coerce types or remove additional properties. The string
`"18"` does not satisfy an `integer` schema, and the returned values are the
original input values.
## Error behavior
Validation failures are normal results: **Is Valid** becomes `false`, and
**Errors** describes every detected problem. By contrast, malformed JSON or an
invalid schema causes the action itself to fail before data can be validated.
JSON does not allow comments, trailing commas, or single-quoted strings.
Parse the schema as JSON and try again.
The schema defines the output because the property exists under `properties`,
but the input data did not provide that own top-level key. Check **Is Valid**
and **Errors** before using the output.
The validator collects all errors it can detect in one pass. Fix the
reported schema-level or parent-value problem first; additional nested
checks may only become meaningful afterward.
# Sub-Workflow
Source: https://learn.workflow.dog/reference/triggers/core/callable
Run this workflow when another workflow calls it.
The **Sub-Workflow** trigger turns a workflow into a reusable operation. Call
it with **Run Workflow**, **Loop Workflow**, **Schedule Workflow**, or an action
that accepts a callable workflow.
## Quick start
Select **When another workflow calls this one** as the trigger.
Add **Data from Trigger**. Its **Data In** output contains the caller's
payload.
Add **Return Data** and connect the value the caller should receive.
In another workflow, add **Run Workflow**, select this workflow, and connect
a payload.
## Trigger data
| Output | Type | Description |
| ----------- | ---- | ----------------------------------- |
| **Data In** | Any | The payload supplied by the caller. |
If the workflow does not use **Return Data**, a waiting caller receives
`null`. Scheduled callers do not wait for a response.
Sub-workflow runs do not accrue usage costs. Recursive calls are rate-limited
to 10 calls per second to prevent infinite recursion.
A failure in this workflow propagates to callers that wait for completion,
such as **Run Workflow** and **Loop Workflow**.
# Mail Hook
Source: https://learn.workflow.dog/reference/triggers/core/email-hook
Run a workflow whenever its unique email address receives a message.
The **Mail Hook** trigger gives the workflow a unique inbound email address.
Send or forward a message to that address to start a run.
## Quick start
The trigger panel displays this workflow's unique address.
Use **Copy Address**, then add it as a recipient, forwarding destination, or
automation target in any email service.
Add **Data from Trigger** and connect the sender, subject, body, or
attachments to later actions.
## Trigger data
| Output | Type | Description |
| ------------------------- | --------------- | ------------------------------------------------------ |
| **Sender Name** | String | Display name of the sender, when provided. |
| **Sender Address** | String | Sender's email address, when provided. |
| **Subject** | String | Message subject. |
| **Plain Text** | String | Plain-text message body. |
| **HTML** | String | HTML message body. |
| **Is Reply?** | Boolean | Whether the message has an `In-Reply-To` header. |
| **Message ID** | String | RFC 822 message identifier without angle brackets. |
| **Plus Path** | String | Text after `+` in the workflow recipient address. |
| **Additional Recipients** | List of strings | To, CC, and BCC addresses other than the hook address. |
| **Attachments** | List of files | Message attachments with filename and content type. |
Some message fields may be `null` when the sending system does not provide
them.
## Route with plus addressing
Add a suffix before the `@` to carry a lightweight routing value:
```text theme={null}
workflow-address+invoices@run.example.com
```
The run receives `invoices` as **Plus Path** while still targeting the same
workflow.
Additional recipient addresses are deduplicated. The exact address that
triggered the workflow is excluded from that list.
Treat inbound email as untrusted input. Validate sender addresses, file types,
and message content before performing sensitive actions.
# Schedule
Source: https://learn.workflow.dog/reference/triggers/core/schedule
Run a workflow on one or more recurring schedules.
The **Schedule** trigger runs a workflow at recurring times. Each schedule has
its own recurrence and IANA timezone, and a workflow can have multiple
schedules.
## Configure a schedule
Choose **Add Schedule**. A new schedule starts at 9:00 AM every day in your
browser's current timezone.
Set an exact time or an interval, then choose days of the month, days of the
week, and months as needed. Common presets include Hourly, Daily, Daily at 9
AM, Weekdays at 9 AM, and Monthly.
Keep the detected timezone or choose another one. The schedule follows that
zone, including daylight-saving changes.
Add more schedules if the workflow should run at several recurring times.
Duplicate recurrence-and-timezone pairs are rejected.
## Trigger data
| Output | Type | Description |
| ------------- | ----------- | ---------------------------------------- |
| **Timestamp** | Date & Time | The time at which the event was emitted. |
Use **Data from Trigger** to access **Timestamp** inside the workflow.
The timestamp records when the scheduled event occurs. Queue load and retries
can cause the workflow itself to begin slightly later.
A schedule is recurring. Delete schedules you no longer need instead of merely
removing their data from the workflow graph.
# Label Added to Email
Source: https://learn.workflow.dog/reference/triggers/gmail/label-added
Start a workflow when Gmail adds a label to a message.
The **Label Added to Email** trigger starts a workflow when one or more labels
are newly applied to a Gmail message. Watch every label change or filter for
one exact label name.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ---------------------------------------------------------- |
| **Google Account** | Google account | Yes | Gmail account to watch. |
| **Label Filter** | String | No | Exact label name to require. Matching is case-insensitive. |
Leave **Label Filter** empty to trigger for any newly added label. A configured
filter matches a complete label name, not a partial name.
## Trigger data
| Output | Type | Description |
| ---------------- | --------------- | ----------------------------------------------------- |
| **Message ID** | String | Gmail ID of the changed message. |
| **Thread ID** | String | Gmail conversation ID. |
| **Added Labels** | List of strings | Names of all labels added in the Gmail history event. |
A single trigger run can contain several **Added Labels**. With a filter set,
the run still exposes the complete list from that label-change event.
## Example: process manually approved mail
Set **Label Filter** to `Approved`, then pass **Message ID** to **Gmail: Get
Message by ID**. Use the retrieved message as the input to the rest of the
approved-mail workflow. This lets a person approve a message in Gmail before
the automation reads its contents or takes action.
## Troubleshooting
Filtering compares complete label names while ignoring capitalization.
`Approved` does not match `Approved/Priority`.
This trigger watches labels being added, not removed.
# New Email
Source: https://learn.workflow.dog/reference/triggers/gmail/new-email
Start a workflow when a new message arrives in a Gmail inbox.
The **New Email** trigger starts a workflow when the connected Gmail account
receives a new inbox message. It can limit runs to subjects containing specific
text and provides parsed message bodies, attachments, and headers.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ------------------------------------------------------------- |
| **Google Account** | Google account | Yes | Gmail inbox to watch. |
| **Subject Filter** | String | No | Required text within the subject. Matching is case-sensitive. |
Leave **Subject Filter** empty to accept every qualifying new inbox message.
The trigger only dispatches messages addressed to the watched mailbox.
## Trigger data
| Output | Type | Description |
| ------------------ | ----------------- | ---------------------------------------------------- |
| **Message ID** | String | Gmail ID of the message. |
| **Thread ID** | String | Gmail conversation ID. |
| **Sender Name** | String | Parsed sender display name, when present. |
| **Sender Address** | String | Parsed sender email address, when present. |
| **Subject** | String | Message subject. |
| **Plain Text** | String | Plain-text MIME content, when present. |
| **HTML** | String | HTML MIME content, when present. |
| **Is Reply?** | Boolean | Whether the message has an `In-Reply-To` header. |
| **Attachments** | List of files | Files downloaded from the message. |
| **Headers** | Object of strings | Lowercase email-header names mapped to their values. |
Message formats vary. **Plain Text**, **HTML**, sender name, or attachments
can be empty when the source message does not contain them.
## Example: triage a support inbox
Set **Subject Filter** to `[Support]`, then pass **Plain Text** through **Remove
Reply Text** before classifying the message. Use the cleaned text and
classification as inputs to **Draft Reply**. Removing quoted conversation
history first helps the classifier and draft focus on the customer's newest
message.
## Troubleshooting
The filter is case-sensitive. Confirm the message arrived in the watched
account's Inbox after the trigger was configured and that the subject
contains the exact filter text.
WorkflowDog-authored mail sent back to the same watched account is excluded
from this incoming trigger to avoid self-triggering loops.
# Sent Email
Source: https://learn.workflow.dog/reference/triggers/gmail/sent-email
Start a workflow when the connected Gmail account sends a message.
The **Sent Email** trigger starts a workflow for messages sent by the connected
Gmail account. Use it to log outbound conversations, synchronize a CRM, or
continue a process after a person sends mail.
## Configuration
| Field | Type | Required | Description |
| -------------------------------- | -------------- | -------- | ---------------------------------------------------------- |
| **Google Account** | Google account | Yes | Gmail account whose sent mail is watched. |
| **Subject Filter** | String | No | Required subject text. Matching is case-sensitive. |
| **Trigger on automated emails?** | Boolean | No | Include messages sent by WorkflowDog. Defaults to `false`. |
Enabling **Trigger on automated emails?** can create an infinite loop when the
resulting workflow sends another Gmail message that matches this trigger. Add
a reliable filter or guard before enabling it.
## Trigger data
| Output | Type | Description |
| ------------------ | ----------------- | ------------------------------------------------ |
| **Message ID** | String | Gmail ID of the sent message. |
| **Thread ID** | String | Gmail conversation ID. |
| **Sender Name** | String | Parsed sender display name, when present. |
| **Sender Address** | String | Parsed sender email address. |
| **Subject** | String | Message subject. |
| **Plain Text** | String | Plain-text MIME content, when present. |
| **HTML** | String | HTML MIME content, when present. |
| **Is Reply?** | Boolean | Whether the message has an `In-Reply-To` header. |
| **Attachments** | List of files | Files downloaded from the sent message. |
| **Headers** | Object of strings | Lowercase header names mapped to their values. |
## Example: log outbound customer mail
Keep **Trigger on automated emails?** off, then use the message headers and
sender details to find the corresponding customer. Connect the customer lookup
to your CRM action and record the sent message as an activity. This captures
mail sent by a person without allowing CRM-generated follow-ups to start the
workflow again.
## Troubleshooting
That is the default safeguard. Enable **Trigger on automated emails?** only
after ensuring the workflow cannot trigger itself repeatedly.
Matching is case-sensitive and looks for the filter as a substring of the
subject. Remove surrounding whitespace and copy the exact capitalization.
# Google Form Response
Source: https://learn.workflow.dog/reference/triggers/google-forms/form-response
Start a workflow when a response is submitted to a Google Form.
The **Google Form Response** trigger starts a workflow for each newly received
response to one form. It exposes the respondent, question IDs, text answers,
and quiz score without requiring a polling action in the workflow.
## Set up the trigger
Select an account with permission to read responses for the form.
Open the form in Google Forms and copy its editing URL.
Paste the URL into **Form URL**, then save the trigger configuration.
Test with a response submitted after the trigger has been configured.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ------------------------------------------------------ |
| **Google Account** | Google account | Yes | Account used to watch the form and read its responses. |
| **Form URL** | URL | Yes | Editing URL of the Google Form to watch. |
When the trigger is initialized, it records the current time and watches for
later responses. It does not intentionally replay existing form submissions.
Each Google notification fetches at most 100 new responses. A burst larger
than that between notifications is not paginated by the current trigger.
## Trigger data
| Output | Type | Description |
| -------------------- | --------------- | ---------------------------------------------------- |
| **Response ID** | String | Google's identifier for the response. |
| **Respondent Email** | String | Respondent email address when the form collects one. |
| **Answers** | List of answers | One item per answered question. |
| **Total Score** | Number | Total score when the form is configured as a quiz. |
Each **Answers** item contains:
| Field | Type | Description |
| ---------------- | --------------- | -------------------------------------------------------------- |
| **Question ID** | String | Google's identifier for the question. |
| **Text Answers** | List of strings | Submitted text values. A question can contain multiple values. |
The trigger currently exposes text answers. File-upload answer details are not
included in the node output.
## Example: route intake responses
Pass **Answers** to a repeat action and inspect **Question ID** for each item.
Route recognized question IDs to the fields they represent, then create or
update the corresponding record. Question IDs are stable identifiers and are
safer for routing than relying on question order.
## Troubleshooting
Confirm the URL is the form's editing URL, the connected account can read
responses, and the response was submitted after the trigger was configured.
Google only supplies an email when the form is configured to collect one.
Checkbox-style or other multi-answer questions can produce more than one
value. Process **Text Answers** as a list.
# Form Submission
Source: https://learn.workflow.dog/reference/triggers/http/form
Start a workflow when an HTML form is submitted.
The **Form Submission** trigger gives a workflow a public form endpoint. It
accepts `POST` form submissions—including uploaded files—and can optionally
serve an HTML form from the same URL on `GET`.
## Configure the form
Open the trigger configuration and copy its unique endpoint.
Set the form's `action` to the trigger URL and its method to `POST`.
Turn on **HTML Response** and enter HTML content. A `GET` request then
returns that HTML instead of running the workflow.
Use an HTTP response action to return a confirmation page, file, redirect,
or status after a `POST`.
```html theme={null}
```
## Configuration
| Setting | Type | Default | Description |
| ----------------- | ------- | ------- | ------------------------------------------------ |
| **HTML Response** | Boolean | Off | Serve the configured HTML for `GET` requests. |
| **HTML Content** | String | Empty | The page returned when HTML Response is enabled. |
## Trigger outputs
| Output | Type | Description |
| ---------- | ----------------- | ------------------------------------------------------------------ |
| **Path** | String | The endpoint path. |
| **Method** | `GET` or `POST` | The request method. |
| **Fields** | Object | Submitted fields and uploaded files. Repeated values become lists. |
| **Query** | Object of strings | Query parameters supplied with a `POST`. |
When **HTML Response** is off, a `GET` request runs the workflow and exposes
its query parameters through **Fields**.
# URL
Source: https://learn.workflow.dog/reference/triggers/http/url
Start a workflow from a general-purpose HTTP endpoint.
The **URL** trigger gives the workflow a unique endpoint that accepts common
HTTP methods and arbitrary text or binary request bodies. Use it when you need
more control than the JSON-only **Webhook** trigger provides.
## Set up the endpoint
Copy the endpoint shown in the trigger configuration.
Call the URL with `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`. Add query
parameters and headers as needed.
End the workflow with an HTTP response action such as **Respond Text**,
**Respond JSON**, **Respond File**, or **Redirect**.
## Trigger outputs
| Output | Type | Description |
| ----------- | ----------------- | --------------------------------------------------------------------------------------- |
| **Path** | String | The path that was called. |
| **Method** | Enum | `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`. |
| **Headers** | Object | Request headers with lowercase names. Cookie and forwarded-address headers are omitted. |
| **Query** | Object of strings | Query parameters. |
| **Body** | String | Text request content, or a base64 string for binary content. |
Requests are limited to 10 MB.
If no response action runs, the caller receives a generic workflow-status
response rather than a custom body.
# Webhook
Source: https://learn.workflow.dog/reference/triggers/http/webhook
Start a workflow from a POST request containing JSON.
The **Webhook** trigger exposes a unique endpoint for services that send JSON
webhooks. It accepts only `POST` requests and parses the request body as JSON.
## Set up a webhook
Open the trigger and copy its unique URL.
Use the URL as the service's webhook or callback destination.
Select properties from **Data**, then finish the workflow with **Respond
Text**, **Respond JSON**, **Respond Status**, or **Redirect** if the sender
expects a response.
## Trigger outputs
| Output | Type | Description |
| ----------- | ----------------- | --------------------------------------------------------------------------------------- |
| **Data** | Any | The parsed JSON request body. |
| **Path** | String | The endpoint path that was called. |
| **Query** | Object of strings | Query parameters. |
| **Headers** | Object | Request headers with lowercase names. Cookie and forwarded-address headers are omitted. |
JSON requests are limited to 100 MB. Other methods return `405 Method Not
Allowed`.
Use the **URL** trigger instead when the sender uses another method, sends
plain text or binary data, or requires access to the request method.
# Triggers
Source: https://learn.workflow.dog/reference/triggers/index
Reference documentation for every trigger available in WorkflowDog.
A trigger is the event that starts a workflow. It can react to an incoming HTTP
request, a schedule, a new message or booking, a form submission, or another
service event.
This reference documents every trigger currently available in the editor.
Browse by package in the navigation or search for the trigger by its node-picker
name.
## How trigger outputs work
When an event arrives, the trigger turns its data into outputs. Those outputs
are the starting values for the rest of the workflow—for example, an incoming
email's sender, an HTTP request body, or a scheduled execution time.
Some triggers change their outputs when you select a different event type or
configuration. Make that choice before connecting the trigger to later actions.
## Test before enabling
Select the account, event type, schedule, route, or other source settings
documented for the trigger.
Send a test request or create a real service event so the workflow receives
the same shape of data it will see in production.
Confirm optional properties, files, and lists before relying on them in
downstream actions.
Once the trigger and downstream actions behave as expected, enable the
workflow so it can receive future events.
External triggers depend on the connected account and the service's delivery
behavior. Removing permissions, deleting a webhook or watch, or disabling the
workflow can stop new events from arriving.
Need a step that runs after a trigger? Browse the complete
[Actions reference](/reference/actions).
# New Email
Source: https://learn.workflow.dog/reference/triggers/outlook/new-email
Start a workflow when a message arrives in an Outlook inbox.
The **New Email** trigger starts a workflow when Microsoft creates a message in
the connected account's Inbox. It can filter by subject and downloads
non-inline attachments for the run.
## Configuration
| Field | Type | Required | Description |
| --------------------- | ----------------- | -------- | -------------------------------------------------- |
| **Microsoft Account** | Microsoft account | Yes | Outlook Inbox to watch. |
| **Subject Filter** | String | No | Required subject text. Matching is case-sensitive. |
Leave **Subject Filter** empty to accept every qualifying new Inbox message.
## Trigger data
| Output | Type | Description |
| ------------------- | ------------- | ------------------------------------------ |
| **Message ID** | String | Microsoft message ID. |
| **Conversation ID** | String | Outlook conversation ID. |
| **Sender Name** | String | Sender display name, when present. |
| **Sender Address** | String | Sender email address, when present. |
| **Subject** | String | Message subject. |
| **Plain Text** | String | Message body requested as text. |
| **HTML** | String | Message body requested as HTML. |
| **Date/Time** | Date | Time the message was received. |
| **Attachments** | List of files | Downloaded non-inline message attachments. |
Messages sent back to the same account by WorkflowDog are excluded when they
carry WorkflowDog's automation header. This prevents common self-triggering
loops.
## Example: archive incoming documents
Set **Subject Filter** to `Statement` to limit runs to statement emails. Connect
**Attachments** to a repeat action, then store each file during the loop. The
workflow creates one run per matching email and processes every non-inline
attachment in that message.
## Troubleshooting
Matching is case-sensitive and searches for the configured text anywhere in
the subject.
The trigger's attachment list is intended for file attachments and does not
include inline attachments.
# New TidyCal Booking
Source: https://learn.workflow.dog/reference/triggers/tidycal/new-booking
Start a workflow when a new TidyCal booking appears.
The **New TidyCal Booking** trigger monitors one connected TidyCal account and
starts the workflow for newly created, non-cancelled bookings.
## Set up the trigger
Select the **TidyCal Account** to monitor, then enable the workflow. The current
implementation monitors all booking types in that account.
WorkflowDog polls TidyCal for new bookings. The workflow may start shortly
after the booking is created rather than at the exact creation instant.
## Trigger outputs
| Output | Type | Description |
| ----------------------------------------------------- | --------------- | --------------------------------- |
| **Booking ID** | Number | The new booking's ID. |
| **Booking Type** | String | The booking type URL slug. |
| **Starts At** / **Ends At** | Date | Appointment boundaries. |
| **Timezone** | String | The booking timezone. |
| **Meeting URL** | String | The meeting link when present. |
| **Contact ID** / **Contact Name** / **Contact Email** | Mixed | Contact details. |
| **Questions** | List of objects | Custom question and answer pairs. |
Cancelled bookings are ignored by the polling source.
# Card Archived
Source: https://learn.workflow.dog/reference/triggers/trello/card-archived
Start a workflow when an open Trello card is archived.
The **Card Archived** trigger starts a workflow when a card's closed state
changes from open to archived on the selected board.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ---------------------------------- |
| **Trello Account** | Trello account | Yes | Account that can access the board. |
| **Board ID** | String | Yes | The Trello board to watch. |
## Trigger data
| Output | Type | Description |
| ----------------------------------------------- | ------ | ---------------------------------------------- |
| **Action ID** / **Action Type** | String | Trello action identifier and type. |
| **Occurred At** | Date | When the card was archived. |
| **Card ID** / **Card Name** | String | The archived card. |
| **Board ID** / **Board Name** | String | The board, when supplied by Trello. |
| **List ID** / **List Name** | String | The card's list, when supplied by Trello. |
| **Previous List ID** / **Previous List Name** | String | Empty unless Trello supplies move data. |
| **Comment Text** | String | Empty for archive events. |
| **Member Creator ID** / **Name** / **Username** | String | The action's creator, when supplied by Trello. |
Reopening a card does not match this trigger. Archiving also matches **Card
Updated** when that trigger watches the same board.
# Card Commented
Source: https://learn.workflow.dog/reference/triggers/trello/card-commented
Start a workflow when a Trello card receives a comment.
The **Card Commented** trigger starts a workflow when someone comments on a
card on the selected Trello board.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ---------------------------------- |
| **Trello Account** | Trello account | Yes | Account that can access the board. |
| **Board ID** | String | Yes | The Trello board to watch. |
## Trigger data
| Output | Type | Description |
| ----------------------------------------------- | ------ | ----------------------------------------------- |
| **Action ID** / **Action Type** | String | Trello action identifier and type. |
| **Occurred At** | Date | When the comment was added. |
| **Card ID** / **Card Name** | String | The commented card. |
| **Board ID** / **Board Name** | String | The board, when supplied by Trello. |
| **List ID** / **List Name** | String | The card's list, when supplied by Trello. |
| **Previous List ID** / **Previous List Name** | String | Empty for comment events. |
| **Comment Text** | String | The text of the new comment. |
| **Member Creator ID** / **Name** / **Username** | String | The comment's creator, when supplied by Trello. |
This trigger responds to newly added comments, not edits or deletions of
existing comments.
# Card Created
Source: https://learn.workflow.dog/reference/triggers/trello/card-created
Start a workflow when a card is created on a Trello board.
The **Card Created** trigger starts a workflow when Trello creates, copies,
emails, or converts a checklist item into a card on the selected board.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ---------------------------------- |
| **Trello Account** | Trello account | Yes | Account that can access the board. |
| **Board ID** | String | Yes | The Trello board to watch. |
## Trigger data
| Output | Type | Description |
| ----------------------------------------------- | ------ | ---------------------------------------------- |
| **Action ID** / **Action Type** | String | Trello action identifier and action type. |
| **Occurred At** | Date | When Trello recorded the action. |
| **Card ID** / **Card Name** | String | The created card. |
| **Board ID** / **Board Name** | String | The board, when supplied by Trello. |
| **List ID** / **List Name** | String | The card's list, when supplied by Trello. |
| **Previous List ID** / **Previous List Name** | String | Empty for normal create events. |
| **Comment Text** | String | Empty for normal create events. |
| **Member Creator ID** / **Name** / **Username** | String | The action's creator, when supplied by Trello. |
The trigger begins watching after its Trello account and board are saved. It
does not replay cards that already exist.
# Card Moved
Source: https://learn.workflow.dog/reference/triggers/trello/card-moved
Start a workflow when a Trello card moves between lists.
The **Card Moved** trigger starts a workflow when a card moves from one list to
another on the selected board.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ---------------------------------- |
| **Trello Account** | Trello account | Yes | Account that can access the board. |
| **Board ID** | String | Yes | The Trello board to watch. |
## Trigger data
| Output | Type | Description |
| ----------------------------------------------- | ------ | ---------------------------------------------- |
| **Action ID** / **Action Type** | String | Trello action identifier and type. |
| **Occurred At** | Date | When the move occurred. |
| **Card ID** / **Card Name** | String | The moved card. |
| **Board ID** / **Board Name** | String | The board containing the card. |
| **List ID** / **List Name** | String | The destination list. |
| **Previous List ID** / **Previous List Name** | String | The source list. |
| **Comment Text** | String | Empty for move events. |
| **Member Creator ID** / **Name** / **Username** | String | The person who moved the card, when available. |
A list move also matches **Card Updated**. Avoid enabling both triggers for
the same downstream work unless duplicate workflow runs are intentional.
# Card Updated
Source: https://learn.workflow.dog/reference/triggers/trello/card-updated
Start a workflow when a Trello card changes.
The **Card Updated** trigger starts a workflow for Trello `updateCard` actions,
including field edits, list moves, archiving, and reopening.
## Configuration
| Field | Type | Required | Description |
| ------------------ | -------------- | -------- | ---------------------------------- |
| **Trello Account** | Trello account | Yes | Account that can access the board. |
| **Board ID** | String | Yes | The Trello board to watch. |
## Trigger data
| Output | Type | Description |
| ----------------------------------------------- | ------ | ------------------------------------------------ |
| **Action ID** / **Action Type** | String | Trello action identifier and type. |
| **Occurred At** | Date | When the update occurred. |
| **Card ID** / **Card Name** | String | The affected card. |
| **Board ID** / **Board Name** | String | The board, when supplied by Trello. |
| **List ID** / **List Name** | String | The current or destination list, when available. |
| **Previous List ID** / **Previous List Name** | String | The source list for a move; otherwise empty. |
| **Comment Text** | String | Empty for update events. |
| **Member Creator ID** / **Name** / **Username** | String | The action's creator, when supplied by Trello. |
This broad trigger includes the events selected by **Card Moved** and **Card
Archived**. Enabling overlapping triggers can start more than one run for the
same Trello action.