Skip to content

Common expression patterns

Recipes for things you'll write often. Copy, adjust, run.


1. Pull a webhook field into an HTTP body

{
  "user_id": "{{ $trigger.payload.userId }}",
  "items":   "{{ $node['Cart'].output.items }}"
}

user_id is placed inside a string, so it is inserted as text and escaped for JSON. items is a value that is exactly one expression, so a list stays a real JSON array. The webhook body is under $trigger.payload, not $trigger.body.


2. Build a URL with path parameters

https://{{ $env.API_HOST }}/users/{{ $trigger.payload.userId }}/orders

Keep the host in a workspace variable ($env) so it can change without editing the workflow.


3. Compose a chat message

:tada: Order {{ $trigger.payload.orderId }} from *{{ $trigger.payload.customerName }}*, total {{ $trigger.payload.amount }}

Mix literal text and expressions freely. Formatting characters such as *bold* are just text to Flero.


4. Date for a file name

report-{{ $node["Today"].output.formatted }}.pdf

Expressions can't format dates. Use two Date & Time nodes:

  1. Now: operation now. Its output has dateTime (ISO 8601).
  2. Today: operation format, input {{ $node["Now"].output.dateTime }}, output format date. Its output has formatted, for example 2026-10-13.

5. Choose between two values

Expressions have no ternary. Branch with an If node and set the value on each branch with a Set node, or use a small Code node:

// Code node "Greeting"
const name = input[0].firstName;
return { greeting: `Hello, ${name || "there"}!` };

Then reference {{ $node["Greeting"].output.greeting }} downstream.


6. Default for a missing field

Use a Set node rule with allowOverwrite off. It writes the key only when it isn't already there:

{
  "allowOverwrite": false,
  "rules": [ { "key": "name", "value": "Anonymous" } ]
}

7. Lower-case an email before comparing

{ "globalTransforms": { "lowercase": ["email"], "trim": ["email"] }, "rules": [] }

Put this Set node before the If that compares the email. {{ $input.email.toLowerCase() }} does not work.


8. Count or sum a list

{
  "transformations": [
    { "operation": "aggregate", "source": "scores", "target": "total", "aggregateOperation": "sum" }
  ]
}

A Data Transform aggregate also does count, average, min and max. To sum a field across a list of objects, use a Code node.


9. Read a later item of a multi-item output

{{ $node["List Orders"].output._items[2].id }}   // third item
{{ $node["List Orders"].output._count }}         // number of items

Without _items, $node["List Orders"].output.id reads the first item.


10. Use the current item inside a Loop

// Inside the Loop body
{{ $input.item.email }}
{{ $input._loopIteration.current }}

The Loop puts each element under item (or the Loop's outputFieldName).


11. Check a webhook signature

Set a secret on the API/Webhook Trigger. Flero then checks the HMAC-SHA256 signature in the X-Hub-Signature-256 or X-Webhook-Secret header on every request, before the run starts.

For providers that sign differently, check the header yourself:

Workflow: Payment event to Has signature?, Has signature? to Process event Payment eventAPI/Webhook Trigger Has signature?IfProcess eventSet

The If node tests {{ $trigger.headers.stripe-signature }} with isNotEmpty. Leave the false port unconnected so unsigned requests stop there.

Then compute and compare the signature with an Encryption & Hashing node (sign or verify), with the key in {{ $env.STRIPE_WEBHOOK_SECRET }}.


12. Idempotency with a processed-events table

Workflow: Payment event to Seen?, Seen? to Already processed?, Already processed? to Record event, Record event to Process event Payment eventAPI/Webhook TriggerSeen?Database Already processed?IfRecord eventDatabaseProcess eventSet
  • Seen? runs SELECT 1 FROM processed_events WHERE id = {{ $trigger.payload.id }}. Values written as {{ }} in SQL are sent as parameters.
  • Already processed? tests whether Seen? returned a row. Leave its true port unconnected so duplicates stop there.
  • Record event inserts the id before the work starts, so a second delivery finds it.

Providers retry webhooks, so the same event can arrive more than once. Recording each event id in your own database means a repeat delivery is skipped, whichever worker runs it.



Found something out of date? This page lives in the Flero docs content set.