SnozeHelp
Reference

Automation triggers, nodes, and expressions

Every automation trigger and node kind, the values each needs and produces, expression paths, templates, operations, predicates, and graph outcomes.

An Automation is a versioned graph. A trigger creates a durable run, nodes read the trigger or earlier outputs, and labelled edges decide what runs next. Published versions are immutable; editing creates draft state until you publish again. Each run keeps its source, trigger payload, node attempts, resolved input, output, and error.

Canonical contract lists

Canonical contract values:

  • manual
  • schedule
  • event
  • webhook

Canonical contract values:

  • action
  • condition
  • transform
  • delay
  • for_each
  • approval
  • connector_operation
  • provider_operation
  • connector_action
  • ai_prompt
  • web
  • sub_automation
  • merge
  • database_record
  • database
  • notify

Canonical contract values:

  • coalesce
  • concat
  • add
  • subtract
  • multiply
  • divide
  • lowercase
  • uppercase
  • length
  • format_payload
  • payload_title
  • format_date
  • add_months
  • extract_text
  • filter_list

Canonical contract values:

  • equals
  • not_equals
  • contains
  • not_contains
  • greater_than
  • greater_than_or_equal
  • less_than
  • less_than_or_equal
  • is_empty
  • is_not_empty
  • exists
  • not_exists

Trigger kinds

Manual trigger manual

Starts only when a person or caller explicitly runs or tests the Automation. It has no trigger-specific settings. The caller may supply a trigger payload; paths under trigger read that payload. A test run is recorded with source test, while an ordinary invocation uses manual.

Schedule trigger schedule

Starts at an interval or cron schedule. An interval requires intervalMinutes. Cron requires both cronExpression and an IANA timezone. The scheduler validates the schedule and records the next run time. Scheduled runs do not acquire an event-catalog payload merely because they run on a clock.

Event trigger event

Listens to one or more catalog definitions. Each saved event contains a definitionId, required resource scope, and optional catalog refinements. The trigger can also carry predicates over the produced event payload. The old single eventType and subjectType fields still decode, but the editor writes the multi-event shape.

Scope is part of subscription matching, not a condition evaluated after every event. An event definition with required scope must save those ResourceRefs, including their human labels. The live definitions and produced paths are in Automation event catalog.

Webhook trigger webhook

Starts when an external caller posts to the Automation’s generated webhook path. Publishing owns the secret, and publishing can rotate it. The parsed request becomes the trigger payload. The trigger config itself has no URL, method, or body schema fields; validate expected data with early Conditions. See Automate with webhooks.

Node kinds

Every node has a stable ID, optional label, canvas position, and optional retry policy: maximum attempts, initial delay, multiplier, and maximum delay. A node may only reference nodes that are guaranteed to have run before it.

Action node action

Requires a saved actionId. Its optional input map resolves expressions and is passed as runtime Action input, along with the typed trigger when available. The node produces the Action run’s result. Because the exact shape belongs to the selected Action, a generic Action node has no static output shape of its own.

Condition node condition

Requires one predicate: left expression, operator, and an optional right expression. It produces { result: boolean } and takes the true or false edge accordingly. Empty and existence operators do not need a right side.

Transform node transform

Requires a map from output keys to expressions. It evaluates every entry and produces that map unchanged in shape. This is the main way to rename paths, combine text, calculate numbers, or reduce a large earlier result to the values later steps need.

Delay node delay

Requires durationSeconds. The run parks durably until its ready time instead of holding a process open. On resumption it produces { resumedAt } as an ISO date. A negative or nonsensical duration is not described as useful behaviour; authors should use a non-negative duration.

For-each node for_each

Its items is either an expression that must resolve to an array, or a database_records source with a fixed or expression-derived database ID and optional limit. It produces { items, count }; each iteration exposes its current value and index through scope, and item/done edges separate the loop body from continuation.

The runtime accepts at most 2,000 items per run. A direct database source pages up to that limit; a searched Database record node is separately capped at 100. maxConcurrency controls how many iterations may progress together.

Approval node approval

Pauses the run with optional human instructions. Resuming requires an approved or rejected decision and may include additional output. The declared downstream value is { decision }. This is a durable wait, not a Condition that guesses consent.

Connector operation node connector_operation

Requires a legacy connector and operation. settings and runtime input are expression maps. At execution Snoze chooses the workspace’s oldest installed connection for that connector; a missing connection is a non-retryable configuration error. The raw connector result becomes the output, and a catalog shape is used when one is declared.

Provider operation node provider_operation

Requires an exact connectionId and operation, with optional resource ID, expression input, and confirmation flag. Picked ResourceRefs are unwrapped to provider IDs at execution. The provider result becomes the output, whose named tokens come from the operation catalog. Provider permissions, mutation flags, and confirmation requirements remain in force.

App action node connector_action

Runs one action of a connected app live, such as linear.create_issue, slack.post_message or stripe.list_invoices. input is an expression map; each value is converted to the type the action’s field expects, and the action’s own output fields are what later nodes can read. The account is the automation’s Run as connection when it belongs to that app, otherwise the step’s chosen workspace connection, otherwise the app’s only workspace connection; a person’s own account (their email) is used only when the automation runs as that person. Actions that cannot be taken back, like posting a message or sending an email, run only after a person turns on “Allow this action to make changes” for the step. A failure the app calls temporary is retried only for reads and actions that are safe to repeat.

Web access node web

Search public web sources, read a webpage, or research named output fields. Search supports domain and publication-date filters; search and page reads can require a maximum cache age. Retrieval time is not the date of a quote: verify the date and units in the source before using time-sensitive values.

Structured research returns typed values with citations for each field and resumes its saved research run while waiting. It supports domain filters, but strict cache-age and publication-date guarantees require search/read steps. Missing, incomplete or insufficient evidence fails the step; use a failure route to handle unavailable sources. Research objectives, field descriptions and source controls share a 25,000-character request budget.

Parallel must be configured for extraction guarantees and structured research. Basic search remains available through configured legacy providers when no source or freshness controls are requested.

AI prompt node ai_prompt

Requires a prompt expression that resolves to non-empty content. Structured values are rendered rather than converted to [object Object]. Choose a model or use Auto, and optionally show the transcript in the workspace chat list.

Access has three choices: Read only, Edit selected items, and Full access. Selected folders include their current descendants; selected databases include their records. Selected-item access allows ordinary reads, while restricting changes to those items and excluding workspace settings and connected-app changes. Every choice still respects the automation’s existing permissions. Older steps retain their saved tool restrictions until an access option replaces them.

Attachments accepts a workspace file ID, a file:// reference, or a list of those values from an earlier step or a database file field. The step uses the same file reading support as AI chat. For Gmail triggers, choose Email → Attachments to pass the files directly: Snoze downloads them through the connected account and stages private AI files when the step runs. They follow chat-file access until explicitly saved to the workspace. Attachment names and counts describe the files but cannot be used to read their contents. A step can read up to 10 files, with a 25 MB limit per email attachment.

Allow user input is off by default. The AI knows it is running an automation, uses the available context, and stops with a blocker if essential input is missing. When enabled, it can ask an essential question or request approval; the run shows Waiting for user input and resumes after a response. Downstream steps wait with it.

It produces text, toolCalls, blocked, and chatId. A blocked turn does not report success or let successors run.

Sub-automation node sub_automation

Requires another automationId and may map expressions into its trigger input. The parent waits for the child run and exposes the child Automation’s result. That shape is dynamic because it belongs to the selected child. Use this for a reused workflow, while avoiding recursive call chains.

Merge node merge

Joins graph paths with optional strategy all or any. all waits for all required incoming paths; any can continue when an eligible path arrives. It produces { merged: true }. It combines control flow, not the object outputs from those branches; use a Transform to construct a combined value.

Database record node database_record

Performs create, update, delete, find, or list in a fixed database or one produced by an earlier node. Create accepts title and field expression maps and returns record ID, title, and data. Update additionally requires a record ID and returns the post-update record. Delete requires a record ID and returns record ID plus deleted: true. Find accepts optional text search and returns found and a record or null. List accepts search and limit and returns records and count.

Unsearched List pages up to a clamped 1–2,000 limit, default 50. Searched List uses the search path and returns at most 100. Writes still enforce writable field kinds, validation, and database permissions.

Database node database

Performs duplicate or instantiate_template. Duplicate needs a fixed or expression-derived source database ID, optional target label, and includeRecords (default true). Instantiate template needs templateId and an optional target label. Both produce { databaseId, label }, which can feed a Database record or For-each node later in the same run.

Send to Inbox node notify

Sends a Snoze notification to workspace members’ Inbox. recipients resolves to user IDs or emails — fixed people, a person field such as a record’s assignee, or a list from an earlier step — and is capped at 50 people per run. title is required and body is an optional message shown under it. link is optional: a record ID, a page or other item ID, or an https:// address that opening the notification shows. A recipient who cannot open the linked item still receives the message, without the link. Recipients who are not members of the workspace are skipped, not an error. Each person’s notification preferences decide whether it also arrives by push or email (push is on and email off by default). It produces { recipients, count, skipped }. A retried step never notifies anyone twice.

Value expressions

A literal expression stores a fixed JSON value. A path expression has source: trigger | node | scope and a string path; node paths also require nodeId. Array indices are decimal path components. A missing segment resolves to undefined.

A template interpolates {{ trigger.path }}, {{ scope.path }}, or {{ nodes.nodeId.path }}. Missing values become an empty string. It is string interpolation, not JavaScript. An operation evaluates its argument expressions first and applies one of the following operators.

Use the Format value button beside an expression to choose a formatting operation and edit its arguments. Before and After use the values you entered or the selected run sample; an unavailable source stays unresolved. Apply saves the expression, while Cancel leaves the original value unchanged. Formatting previews do not execute steps or write records. You can edit an existing formula, nest formulas, or remove its outer formatting to restore the first argument.

First non-empty coalesce

Returns the first argument that is not undefined, null, an empty string, or an empty array. Other objects and zero are not empty.

Join text concat

Converts every argument to text, treats null or undefined as an empty string, and joins without an automatic separator.

Add numbers add

Converts finite numeric values and adds them. A non-numeric argument contributes zero.

Subtract numbers subtract

Starts with the first finite numeric argument, or zero, then subtracts each remaining finite value. A non-numeric remaining argument subtracts zero.

Multiply numbers multiply

Multiplies finite numeric arguments, starting from one. A non-numeric argument is treated as zero and therefore makes the result zero.

Divide numbers divide

Starts with the first finite number, or zero, and divides by each remaining number. Division by zero or by a non-numeric value produces NaN; do not rely on that as a portable downstream value.

Lowercase text lowercase

Converts the first argument to text and applies Unicode-aware JavaScript lowercasing. A null or missing value becomes an empty string.

Uppercase text uppercase

Converts the first argument to text and uppercases it. A null or missing value becomes an empty string.

Value length length

Returns string length, array length, or the number of keys on an object. Other values return zero.

Format payload format_payload

Formats a trigger or step payload into readable text. Its optional second argument controls the payload presentation settings. This is the product’s bounded payload formatter, not arbitrary serialisation.

Payload title payload_title

Derives the short display title Snoze uses for a payload. Use it for labels or notifications when the full formatted payload would be too large.

Format date format_date

Renders an instant (an ISO string such as a schedule trigger’s scheduledFor, or a date field value) as text in a time zone. Arguments: the value, a pattern, and an optional IANA time zone (UTC when omitted). Patterns: month_year (“September 2026”), year_month (“2026-09”), month, year, date (“September 1, 2026”), iso_date (“2026-09-01”, the default). A date without a time of day (a date field’s “2026-09-01”) is that day in every zone. A recurring automation that names a period should derive the name this way rather than typing a month.

Add months add_months

Shifts an instant by whole months in a time zone and returns the ISO instant the same day of the target month (clamped to that month’s length) begins in that zone. A date without a time of day moves to a date: “2026-01-31” plus one month is “2026-02-28” in every zone. Arguments: the value, the number of months (negative for earlier), and an optional IANA time zone. Combine with format_date to label the period that just ended: format_date(add_months(scheduledFor, -1), "month_year", zone).

Extract text extract_text

Arguments: source text, text to start after, and text to stop before. Delimiters are literal, case-sensitive text, not regular expressions. Extraction starts after the first opening delimiter and ends at the first closing delimiter after it. Leave the opening delimiter empty to start at the beginning, or the closing delimiter empty to continue to the end.

For example, extract_text("Order [AB-42] accepted", "[", "]") returns "AB-42". An absent delimiter returns empty text, which can feed coalesce for a fallback. A source that is not text returns no value. The operation does not extract every occurrence or parse arbitrary HTML.

Filter a list filter_list

Arguments: a list, an item field path, a rule, and an optional comparison value. Leave the path empty to compare each whole item, or use a dotted path such as order.amount to read a field within each item. Only the item’s own properties are read. Matching items retain their original values and order; the source list is unchanged.

Rules are equals, not_equals, contains, greater_than, less_than, exists, and is_empty. Equality preserves types: numeric 1 does not equal text "1"; objects and arrays compare by identity, not deep structure. Contains uses case-sensitive text matching or array membership. Greater-than and less-than compare finite numeric conversions; missing or empty values do not qualify. In this list filter, Have a value (exists) excludes null, undefined, empty text, and empty lists, but retains false and zero. Are empty (is_empty) selects those empty values. These two rules do not need a comparison value.

For example, filter_list([{ "amount": 0 }, { "amount": 12 }], "amount", "greater_than", 5) returns [{ "amount": 12 }]. A non-list source returns no value. For literal comparisons, choose Text, Number, or True / false beside Compare with; run-data values retain their source type. A missing sample does not produce a fabricated filtered result in the preview.

Predicate operators

Exactly equal equals

Uses identity equality. Objects and arrays compare by identity rather than by deep structure.

Not exactly equal not_equals

Negates identity equality.

Contains contains

For text, tests a case-sensitive substring after converting the right value to text. For arrays, tests whether an element is identity-equal to the right value. Other left values return false.

Does not contain not_contains

Negates contains, so unsupported left values return true.

Greater than greater_than

Converts both sides to finite numbers and compares them. A failed conversion does not behave like ordinary text comparison and evaluates false.

Greater than or equal greater_than_or_equal

The inclusive numeric comparison, with the same finite-number conversion.

Less than less_than

The strict numeric comparison, with the same finite-number conversion.

Less than or equal less_than_or_equal

The inclusive numeric comparison, with the same finite-number conversion.

Is empty is_empty

True for undefined, null, an empty string, or an empty array. It does not treat an empty object, false, or zero as empty.

Is not empty is_not_empty

Negates the Automation definition of empty.

Exists exists

True when the left side is neither undefined nor null. An empty string exists.

Does not exist not_exists

True only for undefined or null.

Edges and outcomes

Edges may run always, on success or failure, on Condition true or false, or for For-each item and done. Failure edges are explicit recovery paths; a graph can also name a separate failure Automation. The compiler rejects invalid references and graph arrangements before publication, but a valid graph can still fail at run time when live data, a connection, or an external provider is unavailable.

More in Reference

  • Choosing a workspace surfaceChoose between a page, database, dashboard, canvas, view, form, folder, or file when you create workspace content.
  • Workspace item and surface typesEvery kind of item in the workspace tree, which kinds are surfaces, what they open, and where they can nest.
  • Every field typeAll 26 database field kinds, their stored values, settings, defaults, and behaviour in views and automations.
  • Every database view typeTable, list, board, gallery, calendar, timeline, and chart views, including their required fields and saved settings.
  • Filtering recordsEvery view filter operator, its value shape, the field kinds that accept it, and relative date resolution.

Still stuck? Ask the assistant inside Snoze, it reads this same page. Or write tohello@snoze.dev.

Esc

Type to search the help center.