Library Reference

Expression Engine — Quick Reference Cheat Sheet

For Customer v2 flow builders. Use expressions to insert live data — customer names, order details, formatted prices — into your Say, Agent, and Menu prompts. Write {{expression}} in any text field and the engine replaces it with the real value at runtime.


1. How It Works

You call an API, it returns data, and you use {{double braces}} to inject that data into your prompts.

Example: Your flow calls a customer API with result prefix user. Now in any Say or Agent prompt:

Hello {{user_json.customer_name}}!

Your order {{user_json.recent_orders[0].order_id}} for a
{{user_json.recent_orders[0].items[0].product_name}} is
{{user_json.recent_orders[0].status}}.

Today is {{$format($now(), 'MMMM D, YYYY')}}.

Becomes at runtime:

Hello John!

Your order ORD-99281 for a Classic Jacket is Delivered.

Today is April 8, 2026.

That's it. Everything between {{ and }} is evaluated and replaced.

Where You Can Use Expressions

Node Type
Where
Example

Say

Message text

Your balance is {{$format(balance_json.amount, 'currency')}}

Agent

System prompt

Customer: {{user_json.customer_name}}, Loyalty: {{user_json.loyalty_status}}

Menu

Prompt text

You have {{items.length}} options

Important — silent failures: If an expression has a typo or references missing data, it silently produces empty text (no crash, no error shown to the user). Double-check your variable names! The expression {{blance}} won't error — it just disappears from the output.


2. Working with API Data

When an API node runs, the result is stored in session variables using the result prefix you set on the API node.

If you set the prefix to user, you get two variables:

Variable
What It Contains
When to Use

user_result

Text formatted for the AI to read

In Agent system prompts — The customer data: {{user_result}}

user_json

The raw JSON data as a navigable object

When you need specific fields — {{user_json.email}}

user_json is only created when the API returns valid JSON. If the API returns plain text, only user_result is available.

Use dot notation to reach into the data:

Missing Data Won't Break Your Flow

You don't need special syntax for missing data. If a field doesn't exist, it produces empty text in your prompt instead of crashing.

Providing Default Values

Use these when data might be missing and you want to show something instead of blank text.

?? (nullish coalesce) — replaces null or undefined with a fallback:

Ternary ? : — for conditions like "does the array have items?":

When to use which:

Pattern
Use When
Example

??

Field might be null/undefined

{{name ?? 'Guest'}}

? :

Need to check a condition

{{items.length > 0 ? items[0].name : 'none'}}

(nothing)

Empty text is fine

{{user_json.nickname}}

Gotcha: ?? does NOT catch empty string "" or zero 0. If the API returns "", {{name ?? 'Guest'}} still shows blank. Use || instead: {{name || 'Guest'}} catches null, undefined, empty string, 0, and false.

What Values Look Like in Prompts

Value in data
Shows in prompt as
Notes

null

(empty — nothing shown)

undefined

(empty — nothing shown)

"" (empty string)

(empty — nothing shown)

?? does NOT catch this!

"John"

John

42

42

0

0

Shows zero, not empty

true

true

false

false

Shows "false", not empty

[1, 2, 3]

[1,2,3]

Arrays are JSON-stringified

{name: "John"}

{"name":"John"}

Objects are JSON-stringified

When the API Fails

If the API node routes to the failure exit, the result prefix variables (user_result, user_json) are empty or undefined. Any expression referencing them will produce empty text on the failure path.

Also watch for: an API that returns HTTP 200 with an empty results array (e.g., {"results": []}) — this routes to the success exit, but {{results_json.results[0].name}} will be empty since there's no first element.

Tip — unique prefixes: If your flow calls multiple APIs, give each a unique prefix. Reusing the same prefix (e.g., api for both calls) silently overwrites the first result when the second call runs.

Filtering & Transforming Arrays

Use these when you need to pull specific items from a list, count matches, or combine values.

What You Want
Expression
Result

Filter by condition

user_json.orders.filter(x => x.status === 'Delivered')

Matching orders

Get one field from each

user_json.orders.map(x => x.order_id)

["ORD-99281", ...]

Find one item

user_json.orders.find(x => x.order_id === 'ORD-99281')

Single order

Count matches

user_json.orders.filter(x => x.status === 'Pending').length

3

Sum values

user_json.orders.reduce((sum, x) => sum + x.total, 0)

299.97

Any match?

user_json.orders.some(x => x.status === 'Pending')

true/false

All match?

user_json.orders.every(x => x.status === 'Delivered')

true/false

Join to text

user_json.orders.map(x => x.order_id).join(', ')

"ORD-99281, ORD-99282"

Displaying API Data in Prompts


3. Formatting Values

Use $format when you need to display numbers as currency, percentages, or dates in human-readable form.

Number Formatting

Expression
Output

{{$format(1234.5, 'currency')}}

$1,234.50

{{$format(0.15, 'percent')}}

15%

{{$format(1234567, 'number')}}

1,234,567

Date Formatting

Expression
Output

{{$format($now(), 'date')}}

4/8/2026

{{$format($now(), 'time')}}

3:30:00 PM

{{$format($now(), 'datetime')}}

4/8/2026, 3:30:00 PM

{{$format($now(), 'MMMM D, YYYY')}}

April 8, 2026

{{$format($now(), 'MM/DD/YYYY')}}

04/08/2026

{{$format(order_json.delivery_date, 'MMMM D, YYYY')}}

January 14, 2026

Date format tokens: MMMM (January), MMM (Jan), MM (01), D (8), DD (08), YYYY (2026)


4. Operators & Syntax

Use these when building conditions or computing values inside {{expressions}}.

Comparison

Operator
Meaning
Example

===

Equals (strict)

status === 'active'

!==

Not equals

status !== 'cancelled'

> >= < <=

Greater/less than

balance > 1000

Logical

Operator
Meaning
Example

&&

AND

balance > 0 && status === 'active'

||

OR

tier === 'gold' || tier === 'platinum'

!

NOT

!user_json.is_blocked

??

Default for null/undefined

name ?? 'Guest'

Arithmetic

Operator
Example

+ - * /

price * quantity

% (remainder)

index % 2 === 0

** (power)

2 ** 8

Inline If (Ternary)

What's NOT Supported

Expressions are read-only — you can look up and compute values, but not change them.


5. String Methods

Use these when you need to clean up, search, or transform text from API results.

Method
What It Does
Example

.toUpperCase()

ALL CAPS

name.toUpperCase()"JOHN"

.toLowerCase()

all lowercase

name.toLowerCase()"john"

.trim()

Remove whitespace

input.trim()

.includes('text')

Contains?

name.includes('John')true

.startsWith('text')

Starts with?

name.startsWith('J')true

.endsWith('text')

Ends with?

name.endsWith('n')true

.split(',')

Split to array

"a,b,c".split(',')["a","b","c"]

.replace('old','new')

Replace first

"hello".replace('l','r')"herlo"

.replaceAll('old','new')

Replace all

"hello".replaceAll('l','r')"herro"

.slice(0, 5)

Substring

"hello world".slice(0,5)"hello"

.padStart(10, '0')

Pad left

"42".padStart(5,'0')"00042"

.length

Character count

name.length4 (property, no parentheses!)


6. Array Methods

Use these when you need to search, filter, count, or transform lists from API results.

Method
What It Does
Example

[0]

First item

items[0]

.at(-1)

Last item

items.at(-1)

.length

Count

items.length (property, no parentheses!)

.filter(x => ...)

Keep matching

items.filter(x => x.active)

.map(x => ...)

Transform each

items.map(x => x.name)

.find(x => ...)

First match

items.find(x => x.id === 5)

.some(x => ...)

Any match?

items.some(x => x.valid)true/false

.every(x => ...)

All match?

items.every(x => x.valid)true/false

.includes(val)

Contains?

items.includes('apple')true/false

.join(', ')

Join to text

items.join(', ')"a, b, c"

.slice(0, 5)

First N items

items.slice(0, 5)

.reduce((a,x) => ..., 0)

Aggregate

items.reduce((sum, x) => sum + x.price, 0)

.toSorted()

Sort (safe)

items.toSorted()

.toReversed()

Reverse (safe)

items.toReversed()

[...new Set(items)]

Unique values

Remove duplicates

Note: .sort(), .reverse(), .push(), .pop() are blocked because they modify the original data. Use .toSorted(), .toReversed(), and spread [...arr, newItem] instead.


7. Built-In Globals

Use these for math, type conversion, and encoding.

Math

Expression
Result

Math.round(4.5)

5

Math.floor(4.8)

4

Math.ceil(4.2)

5

Math.abs(-5)

5

Math.min(1, 2, 3)

1

Math.max(1, 2, 3)

3

Math.random()

0.0 to 1.0

Type Conversion

Expression
Result

String(123)

"123"

Number("42")

42

Boolean(1)

true

parseInt("42px")

42

parseFloat("3.14")

3.14

typeof value

"string", "number", etc.

JSON & Object

Expression
Result

JSON.parse('{"a":1}')

{ a: 1 }

JSON.stringify(obj)

'{"a":1}'

Object.keys(user)

["name", "email", "age"]

Object.values(user)

["John", "[email protected]", 30]

Encoding

Expression
Result

btoa('hello')

Base64 encode

atob('aGVsbG8=')

Base64 decode

encodeURIComponent('a=b')

URL-encode

decodeURIComponent('a%3Db')

URL-decode


8. $ Helper Functions

These are built-in utility functions (34 total) for dates, formatting, and data access. They all start with $.

Quick Index

$addDays $addHours $addMinutes $addMonths $addSeconds $addYears $bigint $dateDiff $day $dayName $dayOfWeek $escapeHtml $format $fromToon $get $groupBy $guid $hash $hour $isAfter $isBefore $isBetween $isBigInt $isEmpty $isValidDate $minute $month $now $parseDate $sortBy $timeAgo $today $toToon $uuid $year

Date & Time

Use these when you need to show dates, calculate deadlines, or check time-based conditions.

Function
Returns
Example

$now()

Current datetime

"2026-04-08T15:30:00.000Z"

$today()

Current date

"2026-04-08"

$addDays(date, n)

Date + n days

$addDays('2026-01-15', 7)"2026-01-22T..."

$addHours(date, n)

Date + n hours

$addHours($now(), 2)

$addMinutes(date, n)

Date + n minutes

$addMinutes($now(), 30)

$addSeconds(date, n)

Date + n seconds

$addSeconds($now(), 90)

$addMonths(date, n)

Date + n months

$addMonths('2026-01-15', 3)

$addYears(date, n)

Date + n years

$addYears($now(), 1)

$dateDiff(a, b, unit?)

Difference

$dateDiff('2026-01-10', '2026-01-15')5 days

Date Parts

Use these to extract components from a date — useful for time-based logic in prompts.

Function
Returns
Example

$year(date)

Year

$year($now())2026

$month(date)

Month 1-12

$month($now())4

$day(date)

Day 1-31

$day($now())8

$dayOfWeek(date)

0=Sun...6=Sat

$dayOfWeek($now())2

$dayName(date)

Day name

$dayName($now())"Tuesday"

$hour(date)

Hour 0-23

$hour($now())15

$minute(date)

Minute 0-59

$minute($now())30

Date Comparison & Validation

Use these to check if dates are before, after, or within a range.

Function
Returns
Example

$isBefore(a, b)

boolean

$isBefore('2026-01-01', '2026-06-01')true

$isAfter(a, b)

boolean

$isAfter('2026-06-01', '2026-01-01')true

$isBetween(date, start, end)

boolean

$isBetween($today(), '2026-01-01', '2026-12-31')

$isValidDate(str)

boolean

$isValidDate('2026-02-30')false

$parseDate(str)

ISO string or null

$parseDate('January 15, 2026')

$timeAgo(date)

Relative text

$timeAgo('2026-04-06')"2 days ago"

Data Access & Transformation

Use these to safely reach into nested data, sort lists, or check for empty values.

Function
Returns
Example

$get(obj, path, default)

Deep value with fallback

$get(user, 'address.city', 'Unknown')

$groupBy(arr, key)

Grouped object

$groupBy(orders, 'status')

$sortBy(arr, key, dir?)

Sorted array

$sortBy(users, 'lastName')

$isEmpty(val)

boolean

$isEmpty(null)true, $isEmpty([])true

Utility

Use these for generating IDs, hashing data, or optimizing data for AI prompts.

Function
Returns
Example

$guid() / $uuid()

UUID string

"a1b2c3d4-e5f6-..."

$hash(str, algo?)

Hash string

$hash('data', 'sha256')

$escapeHtml(str)

Escaped HTML

$escapeHtml('<b>hi</b>')

$toToon(arr)

Compact table format

For AI-optimized data display

$fromToon(str)

Parsed array

Parse TOON back to objects


9. Common Errors & What They Mean

Error
What Happened
How to Fix

Unknown variable(s): blance

Typo in variable name

Check spelling — did you mean balance?

Unknown method 'toUpper' on string

Wrong method name

Use toUpperCase() instead

'length' is a property, not a method

Called .length() with parentheses

Remove the () — use .length

Unexpected end of expression

Missing closing ), ], or '

Check for unmatched brackets or quotes

Timeout (2000ms)

Expression took too long

Simplify — avoid huge arrays or deep chains

Maximum array length exceeded

Array > 10,000 items

Filter or slice first: .slice(0, 100)

Maximum string length exceeded

String > 100,000 chars

Truncate: .slice(0, 1000)

Security: blocked property access

Accessed __proto__ or constructor

These are blocked for security — use a different approach

Block-body arrow not supported

Used x => { return ... }

Use concise form: x => x.active

(Silent empty text)

Expression failed or data is missing

Check variable names and API prefix — failed expressions produce blank output with no visible error

Last updated

Was this helpful?