powered by

Step Types

Updated Mar 19, 2026
Every workflow is made up of steps. Each step does one focused thing — reading or writing data, calling an API, running custom logic, or branching the flow. Here is a complete guide to every available step type.

Read Data

Fetch records from any entity in your project.

Configuration

Field Description
Entity The entity to read from (e.g. customers, orders)
Limit Maximum number of records to return
Filters Field conditions to narrow results (optional)

Accessing results

Read Data returns an array. Access individual fields like this:

text
{{ $anythink.steps.get_users.data[0].name }}
{{ $anythink.steps.get_users.data[0].email }}

You can also pass the full array to a downstream Create Data step for bulk operations.


Create Data

Insert one or more records into an entity.

Single record

Provide a JSON object with the field values. Template syntax is fully supported:

json
{
  "title": "{{ $anythink.steps.generate.data[0].title }}",
  "status": "draft",
  "author": 2
}

Bulk create

To create multiple records at once, pass an array returned by a Run Script step:

text
{{ $anythink.steps.parse_step.data[0].items }}

This creates one record per item in a single operation, without needing a loop.

Accessing the created record

After creating, the new record including its generated id is available to subsequent steps:

text
{{ $anythink.steps.create_order.data[0].id }}

Update Data

Modify an existing record.

Configuration

Field Description
Entity The entity containing the record
Record ID The ID to update — supports template syntax
Fields JSON object with only the fields to change

Example

Update the status of the record that triggered the workflow:

  • Entity: orders
  • Record ID: {{ $anythink.trigger.data.id }}
  • Fields: {"status": "processed"}

Only the fields you specify are changed. Everything else is untouched.


Delete Data

Remove a record from an entity.

Field Description
Entity The entity to delete from
Record ID The ID of the record to delete

Deletions are permanent and cannot be reversed from within a workflow.


Call an API

Make an HTTP request to any external service — a webhook, a third-party API, or any other system.

Configuration

Field Supports templates Notes
URL No Must be a hardcoded URL
Method GET, POST, PUT, PATCH, DELETE
Headers Yes Key-value pairs
Body Yes JSON request body

Important notes

  • The URL field does not support template syntax. It must be a fixed URL. Put variable parts (IDs, slugs) in the request body instead
  • Do not set Content-Type manually. It is set automatically. Including it yourself will cause the request to fail
  • Headers and body fully support {{ $anythink.steps.step_name.data[0].field }} templates

Example: calling an external AI API

Headers:

json
{
  "x-api-key": "{{ secrets.MY_API_KEY }}",
  "anthropic-version": "2023-06-01"
}

Body:

json
{
  "model": "claude-haiku-4-5-20251001",
  "max_tokens": 500,
  "messages": [
    {
      "role": "user",
      "content": "Summarise: {{ $anythink.steps.get_article.data[0].content }}"
    }
  ]
}

Accessing the response

The full response body is available to downstream steps via data[0]:

text
{{ $anythink.steps.call_api.data[0].content[0].text }}

Run Script

Execute a JavaScript function for custom logic that cannot be expressed as a simple step.

Structure

Your script must return a value. The returned value is automatically wrapped in an array by the platform, so it is always accessed as data[0]:

javascript
return { status: "processed", count: 42 };

// Accessed downstream as:
// {{ $anythink.steps.my_script.data[0].status }}
// {{ $anythink.steps.my_script.data[0].count }}

Accessing previous step data

Previous steps data is available via $anythink:

javascript
var items = $anythink.steps.fetch_items.data;
var trigger = $anythink.trigger.data;

var results = [];
for (var i = 0; i < items.length; i++) {
  if (items[i].status === "active") {
    results.push({ id: items[i].id, name: items[i].name });
  }
}

return { items: results, count: results.length };

Important scripting notes

  • Use var declarations and traditional for (var i...) loops. Modern JS features such as optional chaining and for...of may not be supported in all environments
  • Never return a bare empty array. If your script might return no results, use a flag pattern so downstream steps can detect the empty case:
javascript
return {
  items: results,
  has_results: results.length > 0 ? "yes" : "no"
};
  • The platform wraps your return value in an array. Even if you return { x: 1 }, it arrives downstream as [{ x: 1 }] and is accessed via data[0].x
  • Strings containing newlines must be escaped before including in JSON template bodies. Build and format strings in the script, then return them ready to use

Common use cases

  • Parsing and filtering items from an external API response
  • Deduplicating a list of URLs or records before storing
  • Building a prompt string from multiple data sources
  • Computing derived values such as dates, counts, or formatted strings
  • Transforming an array of items to pass to a bulk Create Data step

Condition

Branch the workflow based on the value of a field. A Condition step has two outputs: one path when conditions are met, and another when they are not.

Configuration

Field Description
Logical operator AND or OR — how multiple conditions combine
Conditions One or more field / operator / value checks

Condition operators

Operator Meaning
eq Equals
neq Not equals
gt Greater than
lt Less than
gte Greater than or equal
lte Less than or equal
contains String contains

Referencing fields in conditions

For fields from a Run Script step, which always wraps output in an array:

text
$anythink.steps.my_script.data[0].my_field

For fields from the trigger:

text
$anythink.trigger.data.status

Using Condition as a gate

A common pattern is using a Condition step as a gate — only continue if a condition is true and stop the workflow otherwise. When the condition is not met, the job shows as "Condition evaluation failed" in job history. This is expected behaviour for a gate, not an error.

Dual-gate pattern

When a workflow fetches items from an external source and then filters them, you may end up with nothing at various stages. Use two Condition gates for safety:

  1. gate_items — did the source return any items at all?
  2. gate_results — did any items survive the filter step?

This prevents a downstream Create Data step from receiving an empty array, which can cause unexpected behaviour.