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
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:
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.
Navigating JSON Fields
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:
??
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
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.
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
{{$format(1234.5, 'currency')}}
$1,234.50
{{$format(0.15, 'percent')}}
15%
{{$format(1234567, 'number')}}
1,234,567
Date Formatting
{{$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
===
Equals (strict)
status === 'active'
!==
Not equals
status !== 'cancelled'
> >= < <=
Greater/less than
balance > 1000
Logical
&&
AND
balance > 0 && status === 'active'
||
OR
tier === 'gold' || tier === 'platinum'
!
NOT
!user_json.is_blocked
??
Default for null/undefined
name ?? 'Guest'
Arithmetic
+ - * /
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.
.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.length → 4 (property, no parentheses!)
6. Array Methods
Use these when you need to search, filter, count, or transform lists from API results.
[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
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
String(123)
"123"
Number("42")
42
Boolean(1)
true
parseInt("42px")
42
parseFloat("3.14")
3.14
typeof value
"string", "number", etc.
JSON & Object
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
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.
$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.
$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.
$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.
$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.
$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
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?