Build
Expressions
Write small formulas to compute values and check conditions in Set variables, Switch and Filter.
Where you write expressions#
An expression is a one-line formula, like in a spreadsheet. You write them in:
- Set variables: each row's value, for example
trim(@full_name). - Switch: the value to route on, and Condition cases such as
value > 100. - Filter: Expression conditions, which must be true or false.
The editor checks what you type as you go. Looks good means it can be read; otherwise it says what's wrong and at which character.
The building blocks#
| Write | Means | Example |
|---|---|---|
@name | The customer's answer to the step called name, or a value from Set variables | @city is Haifa |
#name | Data: from a Catch Hook or HTTP step, Set variables, or the system (#cphone, #channel, #now) | #order.items[0].sku |
"text" or 'text' | Fixed text. Always in quotes | "Tel Aviv" |
12, 3.5 | Numbers, without quotes | @age >= 18 |
true, false, null | Yes, no, and "no value" | exists(#coupon) == false |
[1, 2], {"a": 1} | A list, an object | #status in ["paid", "sent"] |
The text forms {{@city}} and {{#order.id}} work too, so you can paste a variable from a message.
Operators#
| Operator | Does | Example | Result |
|---|---|---|---|
+ - * / % | Math. Number-like text counts as a number | @age + 1 with age 31 | 32 |
+ on two texts | Joins them | "Tel" + " Aviv" | Tel Aviv |
== != < <= > >= | Compare. Numbers as numbers, dates as dates | "31" > 18 | true |
&& || ! (or and or not) | And, or, not | @age >= 18 && @city == "Haifa" | true / false |
in, not in | Is in a list, text or object | "a" in "abc" | true |
?? | Fallback when missing or empty | @nickname ?? "there" | there |
cond ? a : b | If / else | number(@age) >= 18 ? "adult" : "minor" with age 15 | minor |
Functions can also be written after a value: @city.lower() is the same as lower(@city).
Test an expression#
- 1
Open the test
Under the expression, click Test expression.
- 2
Add sample values
In Sample variables, write one per line:
@age = 31,#tour = {"name": "Jaffa"}. If the expression reads fine, click Add the variables this expression uses to list them for you. - 3
Pin the time (optional)
For date functions, add a line like
now = 2026-10-16T09:00+03:00. Include your time-zone offset: without it the time is read as UTC. - 4
Run it
Click Run. The Result shows the value and its type: text, number, true / false, date, list or object. In a Switch condition, also fill in Switch value to test with.
Tests never send messages or alerts, so try as many values as you like, including empty and wrong answers.
Functions: Text#
Click Functions under any expression to see this list and insert a function at the cursor.
| Function | Does | Example | Result |
|---|---|---|---|
length(x) | Characters in a text, items in a list or keys in an object | length("Tel Aviv") | 8 |
lower(text) | Lowercase | lower("YES") | yes |
upper(text) | Uppercase | upper("tlv") | TLV |
trim(text) | Removes spaces at both ends | trim(" Noa ") | Noa |
contains(textOrList, value) | Text contains a part, or a list contains an item | contains(["he", "en"], "en") | true |
startsWith(text, prefix) | Text starts with a prefix | startsWith(#cphone, "972") | true |
endsWith(text, suffix) | Text ends with a suffix | endsWith(@email, ".co.il") | true for noa@shop.co.il |
replace(text, find, with) | Replaces every occurrence (plain text) | replace("050-123-4567", "-", "") | 0501234567 |
split(text, separator) | Splits text into a list | split("red,green,blue", ",") | ["red","green","blue"] |
join(list, separator) | Joins a list into text (default ", ") | join(["Sun", "Mon", "Tue"], " / ") | Sun / Mon / Tue |
substr(text, start, count) | Part of a text; start counts from 0 | substr("ORD-12345", 4) | 12345 |
indexOf(textOrList, value) | Position (from 0), or -1 when missing | indexOf("hello", "l") | 2 |
matches(text, pattern, flags) | Regular expression search; flag "i" ignores case | matches(@id, "^\d{9}$") | true for 123456789 |
Functions: Convert#
| Function | Does | Example | Result |
|---|---|---|---|
text(x) | Converts to text | text(42) | 42 (text) |
number(x) | Converts text such as "42" or "3.5" to a number | number("3.5") + 1 | 4.5 |
int(x) | Whole number part (drops decimals) | int("7.9") | 7 |
bool(x) | true / false; "true", "yes", "1" and "כן" are true | bool("yes") | true |
json(x) | The value as JSON text | json({"id": 7, "tags": ["a"]}) | {"id":7,"tags":["a"]} |
Functions: Numbers#
| Function | Does | Example | Result |
|---|---|---|---|
round(number, digits) | Rounds; halves go away from zero | round(4.567, 2) | 4.57 |
floor(number) | Rounds down | floor(4.9) | 4 |
ceil(number) | Rounds up | ceil(4.1) | 5 |
abs(number) | Absolute value | abs(-3) | 3 |
min(a, b, ...) or min(list) | Smallest number | min(3, 7, 1) | 1 |
max(a, b, ...) or max(list) | Largest number | max([120, 80, 95]) | 120 |
sum(list) | Adds the numbers of a list | sum([10, 20, 5]) | 35 |
Functions: Empty values#
| Function | Does | Example | Result |
|---|---|---|---|
default(x, fallback) | x, or the fallback when x is missing or empty | default(@city, "Tel Aviv") | Tel Aviv when no city |
coalesce(a, b, ...) | The first value that isn't missing or empty | coalesce(@nickname, @full_name, "there") | Noa |
isEmpty(x) | true when x is missing, "", [] or {} | isEmpty(@notes) | true when skipped |
exists(x) | true when x has a value (isn't missing) | exists(#coupon) | false when no coupon was sent |
Functions: Lists and objects#
In these examples #items is [{"sku": "TSHIRT-M", "qty": 2}, {"sku": "CAP", "qty": 1}] and #tours is [{"name": "Jaffa", "price": 80}, {"name": "Galilee", "price": 150}].
| Function | Does | Example | Result |
|---|---|---|---|
keys(object) | The keys of an object | keys({"a": 1, "b": 2}) | ["a","b"] |
values(object) | The values of an object | values({"a": 1, "b": 2}) | [1,2] |
first(list) | First item (empty for an empty list) | first([5, 6, 7]) | 5 |
last(list) | Last item | last([5, 6, 7]) | 7 |
pluck(list, "field") | The field of every object | pluck(#items, "sku") | ["TSHIRT-M","CAP"] |
find(list, "field", value) | First object whose field equals value | find(#items, "sku", "CAP").qty | 1 |
count(list, "field", value) | How many objects have that field value | count(#orders, "status", "paid") | 2 |
unique(list) | Removes repeated items | unique([1, 2, 2, 3]) | [1,2,3] |
sortBy(list, "field", "asc" | "desc") | Sorts by a field; empty values go last | map(sortBy(#tours, "price", "desc"), item.name) | ["Galilee","Jaffa"] |
byLang(object, "HE", "EN") | Picks language versions: name_HE / name_EN become name | byLang(#tour, "HE").name | יפו |
byLang(list, "field", "EN") | Just that field, in that language | byLang(#tours, "name", "EN") | ["Jaffa","Galilee"] |
filter(list, condition) | The items for which the condition is true | filter(#tours, item.price > 100) | the Galilee tour |
map(list, expression) | A new list with the expression applied to each item | map(#tours, item.name) | ["Jaffa","Galilee"] |
In filter() and map(), item is the current item and index its position (from 0). They chain: #tours.filter(item.price > 100).map(item.name) gives ["Galilee"]. byLang() falls back to the second language (default EN) when a version is missing or empty.
Functions: Dates and holidays#
Dates use Israel time (Asia/Jerusalem) unless you pass a time zone. Date answers such as 13/10/2026 work directly in date functions. A date shows as DD/MM/YYYY HH:mm, or DD/MM/YYYY at midnight.
| Function | Does | Example | Result |
|---|---|---|---|
now(timeZone) | Current date and time | now("Europe/London") | 15/10/2026 12:30 |
today(timeZone) | Today at 00:00 | today() | 15/10/2026 |
parseDate(text, format, timeZone) | Reads a date. Without a format: day first, or YYYY-MM-DD | parseDate("10/13/2026 14:30", "MM/DD/YYYY HH:mm") | 13/10/2026 14:30 |
formatDate(date, format) | Date as text, default "DD/MM/YYYY" | formatDate(now(), "DD/MM/YYYY HH:mm") | 15/10/2026 14:30 |
dayOfWeek(date) | 1 = Sunday ... 7 = Saturday | dayOfWeek(parseDate("16/10/2026")) | 6 |
dayName(date, "he") | Name of the day, "en" (default) or "he" | dayName(parseDate("16/10/2026"), "he") | שישי |
isFriday(date) | true on Fridays | isFriday(parseDate("16/10/2026")) | true |
isSaturday(date) | true on Saturdays | isSaturday(parseDate("16/10/2026")) | false |
isWeekend(date) | true on Friday and Saturday | isWeekend(parseDate("17/10/2026")) | true |
addDays(date, days) | Adds days (negative subtracts) | addDays(parseDate("13/10/2026"), 3) | 16/10/2026 |
addHours(date, hours) | Adds hours | addHours(parseDate("13/10/2026 09:00"), 2) | 13/10/2026 11:00 |
addMinutes(date, minutes) | Adds minutes | addMinutes(parseDate("13/10/2026 09:00"), 30) | 13/10/2026 09:30 |
diffDays(from, to) | Calendar days between two dates | diffDays(parseDate("13/10/2026"), parseDate("20/10/2026")) | 7 |
diffMinutes(from, to) | Whole minutes between two dates | diffMinutes(parseDate("13/10/2026 09:00"), parseDate("13/10/2026 10:30")) | 90 |
minutesUntil(date) | Minutes from now (negative when past) | minutesUntil(parseDate("15/10/2026 16:00")) at 15:00 | 60 |
daysUntil(date) | Calendar days from today | daysUntil(parseDate("01/01/2027")) on 15/10/2026 | 78 |
hour(date), minute(date) | Hour 0-23, minute 0-59 | hour(parseDate("13/10/2026 14:30")) | 14 |
day(date), month(date), year(date) | Day 1-31, month 1-12, year | month(parseDate("13/10/2026")) | 10 |
isTimeBetween(date, "09:30", "18:00") | Time of day from start (included) to end (excluded); overnight works | isTimeBetween(parseDate("13/10/2026 23:30"), "20:00", "02:00") | true |
isIsraeliHoliday(date, "public") | Israeli rest-day holiday; "all" adds Chol HaMoed, Purim, Hanukkah and more | isIsraeliHoliday(parseDate("05/12/2026"), "all") | true (Hanukkah) |
isHolidayEve(date) | The day before a rest-day holiday (Erev Chag) | isHolidayEve(parseDate("20/09/2026")) | true |
holidayName(date, "he", "public") | The holiday's name, or empty. Hebrew by default | holidayName(parseDate("21/09/2026"), "en") | Yom Kippur |
isOpenAt(hours, date) | Open at that date and time | isOpenAt(#hours, parseDate("16/10/2026 14:00")) | false with Friday 09:00 - 13:00 |
isOpenNow(hours, timeZone) | Open right now | isOpenNow(#hours) | true / false |
Opening hours for isOpenAt and isOpenNow are an object by day: {"Sunday": "09:00 - 18:00", "Thursday": "09:00-13:00, 16:00-20:00", "Saturday": "closed"}. Use English or Hebrew day names; several ranges with commas; a range past midnight like "20:00 - 02:00" works; a missing day is closed.
Date formats use DD, MM, YYYY, YY, HH, mm and ss in any order with any separators.
Example#
A restaurant decides how to answer a booking request. In a Filter Expression condition:
!isIsraeliHoliday(parseDate(@visit_date)) && dayOfWeek(parseDate(@visit_date)) != 7 && number(@guests) <= 12Test it with @visit_date = 16/10/2026 and @guests = 4: the result is true, so the customer goes to the booking path. With @guests = 20 it's false, and they're offered a call with the manager instead.
Common mistakes#
| What you see | Why | Fix |
|---|---|---|
| Unknown name | Text without quotes, like Tel Aviv | Write "Tel Aviv", or @Tel / #Tel if you meant a variable |
| The expression can't be read | A missing quote or bracket | Close every ", ( and [ |
| Unknown function | A typo, like lenght() | The message suggests the right one: length() |
| Wrong number of values | Too many or too few values | Check the function in the Functions list |
| These values don't fit together | For example number("four") | Ask with a Number step, or use default() |
| The expression is too big / takes too long | Over 2,000 characters, or huge lists | Split it into several Set variables rows |
When an expression fails while a customer is chatting, the bot doesn't stop: Set variables leaves the value empty, Filter treats the condition as false, and Switch follows Default. You get an alert so you can fix it.