Expression functions
This page lists every function you can use in an expression: what it does, what it gives back, the arguments it takes, examples, and the mistakes to look out for. How to write an expression, with variables, texts, numbers and dates, is explained in Expressions. How to work with lists is in its section Lists.
| Group | Functions |
|---|---|
| Comparison | eq, ne, gt, lt |
| Logic | and, or, not, isTrue, isFalse, isEmpty, ifEmpty, ifNull, if |
| Math | inc, add, subtract, multiply, divide, round, roundUp, roundDown, sum, avg, min, max, parseInteger, parseDecimal, parseAmount |
| Text | concat, format, length, contains, containsAny, startsWith, endsWith, match, extract, replace, replaceRegex, trim, lower, upper, padLeft, split, toJson |
| Lists | count, any, first, last, elementAt, filter, select, join, distinct, union, values |
| Dates and times | now, today, dateTime, date, time, parseDateTime, parseDate, parseTime, daysBetween, addDays, addWorkingDays |
Some rules hold for every function:
- Arguments are checked as you build. An argument of the wrong type, or too many or too few, shows as a problem under the expression. "Any value" below means that every type is taken.
- An empty value goes through. Most functions give an empty value, not an error, when they can't do their work. See Empty values.
- Case doesn't matter when texts are compared:
eq("paid", "Paid")is true. This holds for every function that compares or searches text. - Dates and numbers read as text are always written the same way, whatever the server's language:
2026-10-22,14:30:00,2026-10-22 14:30:00, and12.5with a period. Useformatfor any other form.
Comparison
The comparison functions compare two values and give a Boolean. The first argument decides how the second is read: eq({ShipmentNumber}, "17") reads 17 as a number when ShipmentNumber is an Integer. So put the variable first. A second argument that can't be read as the type of the first is a problem as you build: eq({Count}, 1.5), for an Integer Count, says Parameter 2 (Decimal) is not convertable to Integer.
eq
Tests whether two values are equal. Returns a Boolean.
first: any value.second: a value of the same type, or one that can be read as it.
| Expression | Result |
|---|---|
eq("Paid", "PAID") | true |
eq(42, "42") | true |
eq(date({Mail.ReceivedAt}), today()) | true when the mail arrived today |
- Two empty values are equal, and an empty value is never equal to a value. An empty value is not an empty text:
eq({Name}, "")is false when Name is empty. UseisEmpty. - A date compared with a text is read as the date it is, so
eq({Invoice.CreatedAt}, "2026-10-09 10:02:59")matches the file's creation time to the second.
ne
Tests whether two values are not equal: the opposite of eq. Returns a Boolean.
first: any value.second: a value of the same type, or one that can be read as it.
| Expression | Result |
|---|---|
ne("Paid", "Open") | true |
ne(42, "42") | false |
- True when exactly one side is empty, false when both are.
gt
Tests whether the first value is greater than the second. Returns a Boolean.
first: a number, a text, a date or a time.second: a value of the same type, or one that can be read as it.
| Expression | Result |
|---|---|
gt(42, 7) | true |
gt({Amount}, 10000) | true for an amount over 10,000 |
gt({Invoice.CreatedAt}, '2026-10-01 00:00:00') | true for a file created after the start of October |
- Equal values give false, and so does an empty value on either side.
- Two texts are compared as texts, letter by letter:
gt("9", "10")is true. To compare numbers that come in as text, read them first:gt(parseDecimal({Total}), 100). - Numbers are compared as numbers, an Integer with a Decimal included. Dates and times are compared as dates and times.
lt
Tests whether the first value is less than the second. Returns a Boolean.
first: a number, a text, a date or a time.second: a value of the same type, or one that can be read as it.
| Expression | Result |
|---|---|
lt(7, 42) | true |
lt({Invoice.DueDate}, today()) | true when the due date has passed |
- The same rules as
gt: equal values and empty values give false, and two texts are compared as texts.
Logic
and, or and not combine conditions, and if chooses between two values. isEmpty, ifEmpty and ifNull deal with empty values. isTrue and isFalse read a value that may arrive as the text true or false.
and
Tests whether every condition is true. Returns a Boolean.
condition, two or more: each a Boolean, such as a comparison.
| Expression | Result |
|---|---|
and(gt({Amount}, 0), eq({VatAmount}, 0)) | true for a positive amount without VAT |
and(true, true, false) | false |
- It stops at the first false condition: the ones after it aren't worked out. They are still checked as you build.
- An empty condition, such as a Boolean variable that was never set, counts as false.
or
Tests whether at least one condition is true. Returns a Boolean.
condition, two or more: each a Boolean.
| Expression | Result |
|---|---|
or(eq({Status}, "New"), eq({Status}, "Reopened")) | true for either status |
- It stops at the first true condition. An empty condition counts as false.
not
Turns a condition around: true becomes false, and false becomes true. Returns a Boolean.
condition: a Boolean.
| Expression | Result |
|---|---|
not(isEmpty({OrderNumber})) | true when OrderNumber is filled in |
not({IsInternal}) | true when IsInternal is false |
- It takes a Boolean only. For a value that may be a text, such as false, use
isFalse. - An empty condition gives false, not true.
isTrue
Tests whether a value is true, or the text true. Returns a Boolean.
value: any value.
| Expression | Result |
|---|---|
isTrue({IsInternal}) | true when IsInternal is true |
isTrue("TRUE") | true |
isTrue("yes") | false |
- Only true and the text true, in any case, count. Everything else gives false, an empty value included.
isTrueandisFalseare not opposites: both are false for an empty value, or for a text such as yes.
isFalse
Tests whether a value is false, or the text false. Returns a Boolean.
value: any value.
| Expression | Result |
|---|---|
isFalse({IsInternal}) | true when IsInternal is false |
isFalse(contains({Mail.Subject}, "reminder")) | true when the subject doesn't contain reminder |
- Unlike
not, it takes a value of any type. An empty value gives false.
isEmpty
Tests whether a value holds nothing. Returns a Boolean.
value: any value, a list included.
| Expression | Result |
|---|---|
isEmpty({Comment}) | true when Comment was never set, or is an empty text |
isEmpty(" ") | true |
isEmpty({Mail.Attachments}) | true when the mail has no attachments |
- True for an empty value, an empty text, a text of only spaces, and an empty list.
0andfalseare values, so they aren't empty.
ifEmpty
Gives a value, or a fallback when the value holds nothing. Returns the type of the first argument.
value: any value but a list.fallback: a value of the same type, or one that can be read as it.
| Expression | Result |
|---|---|
ifEmpty({Reference}, "unknown") | unknown when Reference is empty or only spaces |
ifEmpty(" ", "Nidaros") | Nidaros |
ifEmpty(0, 42) | 0 |
- "Holds nothing" means what
isEmptytests. Neither argument may be a list.
ifNull
Gives a value, or a fallback when the value was never set. Returns the type of the first argument.
value: any value but a list.fallback: a value of the same type, or one that can be read as it.
| Expression | Result |
|---|---|
ifNull({Reference}, "unknown") | unknown when Reference was never set |
ifNull("", "Nidaros") | an empty text |
ifNull(parseInteger({Quantity}), 0) | 0 when Quantity doesn't hold a whole number |
- It keeps an empty text, because someone set it. Use
ifEmptyto replace that too. - The
parse…functions andextractgive an empty value when they find nothing, soifNullcan supply a default.
if
Chooses between two values by a condition. Returns the type of then.
condition: a Boolean.then: the value when the condition is true.else(optional): the value when it is false, of the same type asthen, or one that can be read as it.
| Expression | Result |
|---|---|
if(gt({Amount}, 10000), "Large", "Small") | Large for an amount of 12,500 |
if(isEmpty({Reference}), {Description}, {Reference}) | Reference, or Description when there is none |
if(eq({Pages}, 1), "1 page", concat({Pages}, " pages")) | 3 pages for 3 |
- Without
else, a false condition gives an empty value. In a mapping row, that leaves the property out. elsemust fit the type ofthen.if({Urgent}, 1.5, 2)works, butif({Urgent}, 2, 1.5)doesn't: a Decimal can't be read as an Integer. Put the Decimal first.thenandelseare both lists, or neither is. Only the value chosen is worked out.
Math
add, subtract, multiply, divide, the rounding functions, sum and avg take Integers and Decimals in any mix, and give a Decimal, also for two whole numbers. An input that takes an Integer needs a whole number back: parseInteger(round(divide({Total}, 3))). An empty argument gives an empty result.
inc
Counts an Integer up, by one or by a step. Returns an Integer.
value: an Integer.step(optional): an Integer; 1 when left out.
| Expression | Result |
|---|---|
inc(41) | 42 |
inc(40, 2) | 42 |
inc(ifNull({Attempt}, 0)) | 1 the first time, when Attempt was never set |
- An empty value gives
0, not1:inc({Attempt})stays at 0 while Attempt is empty. Start it withifNull, as above.
add
Adds two numbers. Returns a Decimal.
value,addend: Integers or Decimals.
| Expression | Result |
|---|---|
add(40, 2) | 42 |
add({Amount}, {ShippingCosts}) | the amount with shipping |
- To add a number of days to a date, use
addDays.
subtract
Subtracts the second number from the first. Returns a Decimal.
value,subtrahend: Integers or Decimals.
| Expression | Result |
|---|---|
subtract(44, 2) | 42 |
subtract({Amount}, {Discount}) | the amount after the discount |
multiply
Multiplies two numbers. Returns a Decimal.
value,factor: Integers or Decimals.
| Expression | Result |
|---|---|
multiply(6, 7) | 42 |
multiply({Amount}, 1.21) | the amount with 21% VAT |
divide
Divides the first number by the second. Returns a Decimal, so a division that doesn't come out even keeps its fraction.
dividend,divisor: Integers or Decimals.
| Expression | Result |
|---|---|
divide(10, 4) | 2.5 |
divide({Amount}, 1.21) | the amount without 21% VAT |
divide({Total}, 0) | empty |
- Dividing by 0 gives an empty value, not an error.
round
Rounds a number to a number of decimals. Returns a Decimal.
value: an Integer or a Decimal.digits(optional): an Integer, the number of decimals; 0 when left out.
| Expression | Result |
|---|---|
round(3.14159, 2) | 3.14 |
round(multiply({Amount}, 1.21), 2) | the amount with VAT, to the cent |
- A half rounds away from zero:
round(2.5)is3andround(-2.5)is-3. - A negative
digitsgives an empty value.
roundUp
Rounds a number away from zero, whatever the digits that are dropped, as a spreadsheet's ROUNDUP does. Returns a Decimal.
value: an Integer or a Decimal.digits(optional): an Integer; 0 when left out.
| Expression | Result |
|---|---|
roundUp(2.01) | 3 |
roundUp(3.14159, 2) | 3.15 |
roundUp(-2.01) | -3 |
roundDown
Rounds a number towards zero, dropping the digits past digits, as a spreadsheet's ROUNDDOWN does. Returns a Decimal.
value: an Integer or a Decimal.digits(optional): an Integer; 0 when left out.
| Expression | Result |
|---|---|
roundDown(2.99) | 2 |
roundDown(3.14159, 2) | 3.14 |
roundDown(-2.99) | -2 |
sum
Adds up the numbers in a list, or one property of every item. Returns a Decimal.
list: a list of numbers, or of items with a number in them.path(optional): the property to add up, as a text, such as"Weight". Needed for a list of items.
| Expression | Result |
|---|---|
sum({Amounts}) | the total of the amounts |
sum({Deliveries}, "Weight") | the total weight |
sum(filter({Lines}, "VatRate", 21), "Amount") | the total of the lines at 21% VAT |
- An item without the property, or without a number in it, adds nothing. An empty list gives
0.
avg
Works out the average of the numbers in a list, or of one property of every item. Returns a Decimal.
list: a list of numbers, or of items with a number in them.path(optional): the property to average, as a text.
| Expression | Result |
|---|---|
avg({OrderLines}, "SalesPrice") | 9.875 for prices of 12.50 and 7.25 |
- An item without a number is left out of the average altogether. With no number at all, the result is empty.
min
Gives the smallest value in a list, or of one property of every item. Returns the type of the items, or of the property.
list: a list.path(optional): the property to compare, as a text. Needed for a list of items.
| Expression | Result |
|---|---|
min({Deliveries}, "Weight") | the lowest weight |
min({OrderLines}, "DeliveryDate") | the earliest delivery date |
- The values are compared as numbers when they all are, texts holding a number included (
"9"is less than"21"); otherwise as dates when they all are; otherwise as texts. - Empty values are left out. An empty list gives an empty value.
max
Gives the largest value in a list, or of one property of every item. Returns the type of the items, or of the property.
list: a list.path(optional): the property to compare, as a text. Needed for a list of items.
| Expression | Result |
|---|---|
max({Lines}, "Quantity") | the largest quantity |
max({Mail.Attachments}, "CreatedAt") | when the newest attachment was created, as a DateTime |
- The same rules as
min.
parseInteger
Reads a value as a whole number. Returns an Integer, or an empty value when the value isn't a whole number.
value: any value but a list.
| Expression | Result |
|---|---|
parseInteger(" 007 ") | 7 |
parseInteger("42.5") | empty |
ifNull(parseInteger({Quantity}), 0) | 0 when Quantity holds no whole number |
- Spaces around a text are ignored. A Decimal without a fraction, such as
42.0, counts. - A number with a fraction is not rounded: it gives an empty value. Round it first with
round.
parseDecimal
Reads a value as a number written with a period. Returns a Decimal, or an empty value when the value isn't a number.
value: any value but a list.
| Expression | Result |
|---|---|
parseDecimal("8.5") | 8.5 |
parseDecimal(42) | 42 |
parseDecimal("8,5") | empty |
- Only a period separates the decimals, and there is no thousands separator. For an amount written the Dutch way, such as 8,50, use
parseAmount.
parseAmount
Reads an amount as people write it, the Dutch or the English way. Returns a Decimal, or an empty value when the value isn't an amount.
value: any value but a list.
| Expression | Result |
|---|---|
parseAmount("12,50") | 12.50 |
parseAmount("1.250,00") | 1250.00 |
parseAmount("1,250.00") | 1250.00 |
- A separator followed by exactly three digits is a thousands separator:
2.500and2,500are both two thousand five hundred. - Thousands must be grouped in threes:
12.3456is not an amount.500,is 500, and,50is 0.50. - A value that already is a number passes through as it is:
parseAmount(1.234)is1.234, not 1234.
Text
The text functions read their arguments as text: a number as 12.5, a date as 2026-10-22. Searching and comparing ignores case.
contains, containsAny, startsWith and endsWith don't search a single date, time or date and time: that is a problem as you build. Compare it as a date, or write it as text with format first: startsWith(format({Invoice.CreatedAt}, "yyyy-MM"), "2026-10").
Regular expressions. match, extract and replaceRegex take a pattern, a regular expression in the .NET style. The pattern is found anywhere in the text, ignoring case, unless it starts with ^ or ends with $. Some of its building blocks:
| Pattern | Matches |
|---|---|
\d, \d+, \d{4} | a digit, one or more digits, exactly four digits |
\s* | any number of spaces |
. | any character; \. is a period |
^, $ | the start, the end of the text |
[A-Z] | one letter |
(…) | a group, which extract and replaceRegex can refer to |
a|b matches either a or b. A pattern typed in that isn't a valid regular expression is a problem as you build.
concat
Joins values into one text. Returns a text (String).
value, any number: any values.
| Expression | Result |
|---|---|
concat("Hello, ", {Name}, "!") | Hello, Anna! |
concat({OrderId}, ".", {OrderLineId}) | 50.550 |
- Empty values add nothing. A complex value, such as a whole Shipment, is skipped: use its properties.
concat({Days})is the simple way to turn a number into a text.
format
Writes a value as text in a .NET format. Returns a text (String).
value: any value.format: a text: a format such as"0.00", or a pattern in which{0}stands for the value, such as"Invoice {0}"or"{0:D5}".
| Format | Value | Result |
|---|---|---|
"0.00" | 2450.5 | 2450.50 |
"N2" | 2450.5 | 2,450.50 |
"D5" | 42 | 00042 |
"dd-MM-yyyy" | '2026-10-22' | 22-10-2026 |
"yyyy-MM-dd HH:mm" | '2026-10-22 14:30:00' | 2026-10-22 14:30 |
"Invoice {0}" | 42 | Invoice 42 |
So format({Amount}, "0.00") gives 12.50 for 12.5, and format(today(), "dd-MM-yyyy") gives 22-10-2026.
- The result is the same on every server: a period for the decimals and a comma between thousands, and day and month names in English. For an amount the Dutch way, replace the period:
replace(format({Amount}, "0.00"), ".", ",")gives12,50. - A format that doesn't fit the value, such as
D5for a Decimal, gives the value as plain text. - The result is a text, so it can't be compared as a date. Use
datefor that.
length
Counts the characters in a text. Returns an Integer.
text: a String, not a list.
| Expression | Result |
|---|---|
length("Nidaros") | 7 |
length({PostalCode}) | 6 for 1234AB |
- It takes only a text. A number, a date or a list is a problem as you build. To count the items of a list, use
count. To test whether a value is filled in, useisEmpty. - An empty value gives
0. Spaces count:length(" ")is2.
contains
Tests whether a text contains another, or whether a list holds a value. Returns a Boolean.
haystack: any value, or a list.needle: the text to look for.
| Expression | Result |
|---|---|
contains({Mail.Subject}, "reminder") | true for Second REMINDER |
contains({Tags}, "Spider") | true when Tags is Nidaros, Spider |
contains({Tags}, "Spi") | false: in a list, the whole item must match |
- An empty needle never matches. A test against a keyword that isn't filled in doesn't fire.
- When the first argument is a list, it tests whether one of its items equals the needle, not whether one contains it. To search inside the items, use
anywith"contains".
containsAny
Tests whether a text contains any of a list of texts. Returns a Boolean.
haystack: any value, or a list.list: a list of the texts to look for.
| Expression | Result |
|---|---|
containsAny({Mail.Subject}, {SkipKeywords}) | true for a subject with any of the keywords |
containsAny({Mail.Subject}, split("urgent;asap", ";")) | true for ASAP: invoice 42 |
- The second argument must be a list. Empty items in it never match, so a list from
splitwith a separator at the end doesn't match everything. - When the first argument is a list too, it tests whether the two lists share an item. See E-mail values for an example.
startsWith
Tests whether a value begins with a text. Returns a Boolean.
value: any value but a date or a time, read as text.prefix: a text.
| Expression | Result |
|---|---|
startsWith({Mail.Subject}, "RE:") | true for Re: invoice 42 |
startsWith(format({Invoice.CreatedAt}, "yyyy-MM"), "2026-10") | true for a file created in October 2026 |
- An empty prefix never matches.
endsWith
Tests whether a value ends with a text. Returns a Boolean.
value: any value but a date or a time, read as text.suffix: a text.
| Expression | Result |
|---|---|
endsWith({Mail.From.Address}, "@nidaros.nl") | true for a sender in that domain |
- An empty suffix never matches.
match
Tests whether a value matches a regular expression. Returns a Boolean.
value: any value, read as text.pattern: a text, the regular expression.
| Expression | Result |
|---|---|
match({Mail.Subject}, "^RE:") | true for a subject that starts with RE: |
match({Iban}, "^NL\d{2}[A-Z]{4}\d{10}$") | true for a well-formed Dutch IBAN |
- Without
^and$, the pattern may be anywhere:match({Code}, "\d{4}")is true for AB12345. - An empty pattern never matches. A pattern from a variable that isn't valid gives false.
extract
Gives the part of a value that a regular expression finds. Returns a text (String), or an empty value when nothing is found.
value: any value, read as text, or a list.pattern: a text, the regular expression.group(optional): the number of a group in the pattern, counting from 1, or the name of a named group. The whole match when left out.
| Expression | Result |
|---|---|
extract("Invoice 2026-0042", "\d{4}-\d{4}") | 2026-0042 |
extract("Invoice 2026-0042", "(\d{4})-(\d{4})", 2) | 0042 |
ifNull(extract({Mail.Subject}, "order (\d+)", 1), "unknown") | unknown when the subject holds no order number |
- The first match counts. Nothing found gives an empty value, so
ifNullcan supply a default. - For a list, the items are tried in order, and the first one that holds a match answers:
extract(select({OrderLines}, "Reference"), "PRID:(\d+)", 1).
replace
Replaces every occurrence of a text by another. Returns a text (String).
value: any value, read as text.search: the text to find, as it is: not a pattern.replacement: the text to put in its place.
| Expression | Result |
|---|---|
replace({Description}, "[StudentName]", {StudentName}) | Contribution Zoë de Vries for Contribution [StudentName] |
replace(format({Amount}, "0.00"), ".", ",") | 12,50 |
- The search ignores case, so
[studentname]is replaced too. - An empty
searchchanges nothing. An emptyreplacementremoves what is found. - To fill in more than one placeholder, nest it:
replace(replace({Text}, "[Name]", {Name}), "[Number]", {Number}). Or use a template.
replaceRegex
Replaces every match of a regular expression by a text. Returns a text (String).
value: any value but a list, read as text.pattern: a text, the regular expression.replacement: the text to put in its place.$0stands for the whole match,$1for the first group,${name}for a named group, and$$for a dollar sign.
| Expression | Result |
|---|---|
replaceRegex("Invoice 2026-0042", "\d{4}-(\d{4})", "no. $1") | Invoice no. 0042 |
replaceRegex({Phone}, "\s", "") | 0612345678 for 06 1234 5678 |
- A replacement that holds a
$from a variable is still read as one of the substitutions. Double its dollar signs first:replace({Name}, "$", "$$"). - A pattern built from a list of terms, such as
concat("\b(", join({Terms}, "|"), ")\b"), finds any of them. Characters such as.,(and+in a term then mean something to the pattern. - An empty pattern, or one from a variable that isn't valid, leaves the value as it is.
trim
Removes the spaces at the start and the end of a value. Returns a text (String).
value: any value, read as text.
| Expression | Result |
|---|---|
trim(" Jansen BV ") | Jansen BV |
eq(trim({Invoice.Name}), trim({Customer.CompanyName})) | true when only the spaces differ |
- An empty value gives an empty text.
lower
Writes a value in lower case. Returns a text (String).
value: any value, read as text.
| Expression | Result |
|---|---|
lower("NIDAROS") | nidaros |
- Comparisons already ignore case, so
loweris for producing a value, not for comparing one. An empty value gives an empty text.
upper
Writes a value in upper case. Returns a text (String).
value: any value, read as text.
| Expression | Result |
|---|---|
upper(trim({Code})) | AB12 for ab12 with a space before it |
concat(upper({Administration}), " - ", {InvoiceNumber}) | NIDAROS - 42 |
padLeft
Fills a value up on the left to a length. Returns a text (String).
value: any value, read as text.width: an Integer, the length to reach.character(optional): the character to fill with; a space when left out. Only its first character is used.
| Expression | Result |
|---|---|
padLeft("42", 5, "0") | 00042 |
padLeft({Code}, 4, "0") | 0007 for 7 |
- A value that is already as long as
widthstays as it is. Awidthbelow 0 or above 1000 changes nothing. - For a number,
format({Number}, "D5")does the same.
split
Splits a text into a list at a separator. Returns a list of texts (String).
value: any value, read as text.separator: a text.
| Expression | Result |
|---|---|
split("Nidaros;Spider", ";") | a list of Nidaros and Spider |
split("Nidaros ; Spider", ";") | the same list: each item is trimmed |
count(split("Nidaros;Spider;", ";")) | 3 |
- Empty items are kept, so a separator at the end gives an empty last item.
- An empty separator gives a list of one item, the whole value.
toJson
Writes a value as JSON text, for an HTTP body, a file or a message. Returns a text (String).
value: any value, a list or a complex value included.nameCase(optional): how property names are written, typed in as a text:"asIs"(when left out),"camelCase","pascalCase","snakeCase"or"kebabCase". It can't be a variable.
nameCase | VATNumber | orderLine |
|---|---|---|
asIs | VATNumber | orderLine |
camelCase | vatNumber | orderLine |
pascalCase | VATNumber | OrderLine |
snakeCase | vat_number | order_line |
kebabCase | vat-number | order-line |
| Expression | Result |
|---|---|
toJson({Order}) | {"OrderNumber":"SO-1001","Total":12.50} |
toJson({Order}, "camelCase") | {"orderNumber":"SO-1001","total":12.50} |
toJson({Tags}) | ["urgent","reminder"] |
nameCaseapplies to every property name, at every depth.- Dates are written as
"2026-10-22","14:30:00", and"2026-10-22T14:30:00+02:00". An empty value givesnull. - The JSON is on one line. Characters such as
<and&are written as they are, so don't put the text into an HTML page as it is.
Lists
These functions work on a list: a variable marked as a list, a list property such as {Mail.To}, or a function that gives a list, such as filter, select or split. The aggregates sum, avg, min and max are under Math, and contains and containsAny under Text. See also Lists in the chapter on expressions.
- A path inside these functions is a text in quotes, read from each item:
"Weight","Address.Country".""is the item itself, for a list of plain values such as texts. A path can't go into a list of its own, and there is no[0]. - A comparison in
any,countandfilteris one of"eq","ne","gt","lt","contains","startsWith","endsWith"and"match", typed in as a text. Each means what the function of that name means. Without one, the comparison iseq. - An item without the property never matches, whatever the comparison, except
"ne", for which it matches.eqagainst""doesn't match it either. - A function that requires a list says so as you build when it gets one value.
count
Counts the items of a list, or the items that match. Returns an Integer.
list: a list.path,comparison,value(optional): the property to test, the comparison, and the value to compare with. Givepathandvaluetogether, with or withoutcomparison.
| Expression | Result |
|---|---|
count({Deliveries}) | how many deliveries there are |
count({Deliveries}, "Address.Country", "NL") | how many go to the Netherlands |
gt(count({Mail.Attachments}, "Extension", "endsWith", "ml"), 0) | true for at least one XML or HTML attachment |
- Use
countfor a list:lengthcounts the characters of a text, and doesn't take a list. - A value that isn't a list gives
0.
any
Tests whether a list has any items, or any items that match. Returns a Boolean.
list: a list.path,comparison,value(optional): as forcount.
| Expression | Result |
|---|---|
any({Mail.Attachments}) | true when there is at least one attachment |
any({Deliveries}, "Weight", "gt", 100) | true when a delivery weighs over 100 |
any({Tags}, "", "urgent") | true when Tags holds urgent |
any({List})means the same asgt(count({List}), 0).- A path without a value, two arguments in all, is a problem as you build.
first
Gives the first item of a list, or the first value of a property. Returns the type of the items, or of the property.
list: a list.path(optional): the property to read, as a text.
| Expression | Result |
|---|---|
first({Deliveries}) | the first delivery |
first({Mail.To}, "Address") | the first recipient's address |
first(filter({OrderLines}, "OrderLineId", {Line.OrderLineId})) | the order line with that id |
- Empty items, and items without the property, are skipped. An empty list gives an empty value.
- A single value counts as a list of one. Data converted from XML holds a list of one as the item itself, so
first({OrderLine.Products})reads one product and a list of them alike.
last
Gives the last item of a list, or the last value of a property. Returns the type of the items, or of the property.
list: a list.path(optional): the property to read, as a text.
| Expression | Result |
|---|---|
last({Deliveries}) | the last delivery |
last(split({File.Url}, "/")) | the file name at the end of a URL |
- The same rules as
first.
elementAt
Gives the item of a list at a position, counting from 0. Returns Any.
list: a list.index: an Integer; 0 is the first item.
| Expression | Result |
|---|---|
elementAt({Tags}, 0) | Nidaros when Tags is Nidaros, Spider |
elementAt(split("A;B;C", ";"), 2) | C |
- A position past the end, or below 0, gives an empty value.
- The result is Any, so the designer doesn't check what it is, and a path can't go on from it:
elementAt({Mail.Attachments}, 0).FileNameis an error. Select the property first:elementAt(select({Mail.Attachments}, "FileName"), 0). For the first or last item,firstandlastkeep the type.
filter
Gives the items of a list that match. Returns a list of the same type as the list.
list: a list.path: the property to test, as a text.comparison(optional): the comparison;"eq"when left out.value: the value to compare with.
| Expression | Result |
|---|---|
filter({Deliveries}, "Address.Country", "NL") | the deliveries to the Netherlands |
filter({Mail.Attachments}, "Extension", ".pdf") | the PDF attachments, as a list of File |
filter(filter({Mail.Attachments}, "Extension", ".pdf"), "Name", "startsWith", "invoice") | the PDF attachments whose name starts with invoice |
- The result is a list again, so it can go into
count,select,firstor anotherfilter. - A value that isn't a list gives an empty list.
select
Gives one property of every item, as a list of its own. Returns a list of the property's type.
list: a list.path: the property to take, as a text, such as"Address"or"Sender.Country".
| Expression | Result |
|---|---|
select({Deliveries}, "Recipient") | the recipients, as a list of texts |
join(select({Mail.To}, "Address"), "; ") | orders@nidaros.nl; finance@nidaros.nl |
contains(select({Mail.Attachments}, "Name"), "invoice") | true when an attachment is named invoice |
- This is how to read through a list, where a path can't:
{Mail.To.Address}is an error,select({Mail.To}, "Address")the list of addresses. - Items without the property are left out, so
count(select(…))counts values, wherecount(…)counts items. - A path that names a list property, such as
select({Mails}, "To"), gives Any.
join
Joins the items of a list into one text, with a separator between them. Returns a text (String).
list: a list of texts, numbers or Booleans.separator: a text.
| Expression | Result |
|---|---|
join({Tags}, ", ") | Nidaros, Spider |
join(select({Mail.To}, "Address"), "; ") | the recipients on one line |
- Items that are complex values, such as e-mail addresses, are skipped without a word:
join({Mail.To}, "; ")gives an empty text. Useselectfirst, as in the second example.
distinct
Gives a list without repeats, or the different values of one property. Returns a list of the type of the items, or of the property.
list: a list.path(optional): the property to take, as a text.
| Expression | Result |
|---|---|
distinct({OrderLines}, "VatRate") | each VAT rate once |
join(distinct({FileNames}), ", ") | each file name once, on one line |
- The first of each value is kept, in order. Texts are compared ignoring case, and numbers by their value:
1and1.0are the same. - Empty values are left out.
union
Puts the items of several lists together, each once. Returns a list of the lists' type, or of Any where they differ.
list, one or more: lists.
| Expression | Result |
|---|---|
union({Settings.ResultsCc}, {School.ResultsCc}) | every address in either list, once |
union({Tags}) | Tags without repeats or blanks |
- Repeats are found as by
distinct:X@school.nlandx@school.nlare one. - Texts are trimmed, and empty items and blank texts are left out. A list that isn't set adds nothing.
values
Gives the values of an object's properties, as a list. Returns a list of Any.
object: one value, not a list.
| Expression | Result |
|---|---|
values({OrderLine.DeliveryAddresses}) | the delivery addresses, as a list |
count(values({OrderLine.DeliveryAddresses})) | how many addresses there are |
- For data that names each item, such as XML converted to JSON, where DeliveryAddresses holds a DeliveryAddress1 and a DeliveryAddress2.
- Anything other than an object, an empty value included, gives an empty list.
Dates and times
Now and today are on the clock of the server, or of the organization's time zone where it has one. A date and time that comes in with a time zone, such as 2026-10-09T08:02:59Z, is read as that moment on the same clock.
Text is read as a date in these forms only. A form such as 10/9/2026 is not read, because it could be either day.
| Kind | Forms |
|---|---|
| DateTime | 2026-10-22 14:30:00, 2026-10-22T14:30:00, 22-10-2026 14:30:00, and ISO 8601 with a time zone |
| Date | 2026-10-22, 22-10-2026 |
| Time | 14:30:00, 14:30 |
A date with the day first is read day first: 01-02-2026 is 1 February. For other forms, give dateTime, date or time a format.
Two ways to read a date. dateTime, date and time take a text or a date, can use a format, and give the current value without an argument. parseDateTime, parseDate and parseTime take any value, such as a spreadsheet cell or an Any output, and give an empty value for anything that isn't exactly that kind of value, so ifNull can supply a default.
dateTime, date, time | parseDateTime, parseDate, parseTime | |
|---|---|---|
| Takes | a text, a date or a time | any value but a list |
| Without an argument | the current value | a problem as you build |
| A DateTime, for a Date or a Time | its date or time part | empty |
| A format | optional | not taken |
| Spaces around the text | part of the text | ignored |
| A text it can't read | empty | empty |
now
Gives the current date and time. It takes no arguments. Returns a DateTime.
| Expression | Result |
|---|---|
now() | 2026-10-22 14:30:00 |
format(now(), "HH:mm") | 14:30 |
- The same as
dateTime().
today
Gives the current date. It takes no arguments. Returns a Date.
| Expression | Result |
|---|---|
today() | 2026-10-22 |
addWorkingDays(today(), 2) | 2026-10-26, when today is Thursday 22 October 2026 |
- The same as
date().
dateTime
Gives the current date and time, or reads a value as one. Returns a DateTime.
value(optional): a text or a DateTime.format(optional): a text, the .NET format the text is in.
| Expression | Result |
|---|---|
dateTime("22-10-2026 14:30:00") | 2026-10-22 14:30:00 |
dateTime("20261022 143000", "yyyyMMdd HHmmss") | 2026-10-22 14:30:00 |
- A Date isn't taken: it has no time.
- A format only goes with a text. A text it can't read gives an empty value.
date
Gives the current date, reads a value as a date, or takes the date of a DateTime. Returns a Date.
value(optional): a text, a Date or a DateTime.format(optional): a text, the .NET format the text is in.
| Expression | Result |
|---|---|
date("20261022", "yyyyMMdd") | 2026-10-22 |
date('2026-10-22 14:30:00') | 2026-10-22 |
eq(date({Mail.ReceivedAt}), today()) | true when the mail arrived today |
- The result is a Date, which can be compared.
formatgives a text, which can't be compared as a date.
time
Gives the current time, reads a value as a time, or takes the time of a DateTime. Returns a Time.
value(optional): a text, a Time or a DateTime.format(optional): a text, the .NET format the text is in.
| Expression | Result |
|---|---|
time("14:05") | 14:05:00 |
gt(time({Mail.ReceivedAt}), '17:00:00') | true for mail that arrived after five |
parseDateTime
Reads a value as a date and time. Returns a DateTime, or an empty value when the value isn't one.
value: any value but a list.
| Expression | Result |
|---|---|
parseDateTime("22-10-2026 14:30:00") | 2026-10-22 14:30:00 |
parseDateTime("2026-10-22") | empty: a date without a time |
- A Date isn't taken for midnight: it gives an empty value.
parseDate
Reads a value as a date. Returns a Date, or an empty value when the value isn't one.
value: any value but a list.
| Expression | Result |
|---|---|
parseDate("9-7-2026") | 2026-07-09 |
ifNull(parseDate({Row.Date}), today()) | today, when the cell holds no date |
- A DateTime, or a text that holds one, gives an empty value. To take the date of a DateTime, use
date.
parseTime
Reads a value as a time of day. Returns a Time, or an empty value when the value isn't one.
value: any value but a list.
| Expression | Result |
|---|---|
parseTime("9:30") | 09:30:00 |
parseTime("25:00") | empty |
- A DateTime gives an empty value. To take the time of a DateTime, use
time.
daysBetween
Counts the calendar days from one date to another. Returns an Integer.
from: a Date or a DateTime.to: a Date or a DateTime.
| Expression | Result |
|---|---|
daysBetween('2026-07-01', '2026-07-09') | 8 |
daysBetween('2026-07-09', '2026-07-01') | -8 |
gt(daysBetween({LastReminder}, today()), 7) | true more than a week after the last reminder |
- The times are dropped first, so the hour of the day never matters, and a Date and a DateTime can be mixed.
addDays
Moves a date a number of days forward or back. Returns a Date or a DateTime: the type of date.
date: a Date or a DateTime.count: an Integer; negative to go back.
| Expression | Result |
|---|---|
addDays('2026-10-22', 14) | 2026-11-05 |
addDays(today(), -7) | a week ago |
lt({Invoice.DueDate}, addDays(today(), 14)) | true when the invoice is due within two weeks |
- A DateTime keeps its time of day.
addWorkingDays
Moves a date a number of working days, Monday to Friday, forward or back. Returns a Date or a DateTime: the type of date.
date: a Date or a DateTime.count: an Integer; negative to go back.
| Expression | Result |
|---|---|
addWorkingDays('2026-10-22', 2) | 2026-10-26: Thursday to Monday |
addWorkingDays('2026-10-24', 1) | 2026-10-26: Saturday to Monday |
addWorkingDays('2026-10-24', -1) | 2026-10-23: Saturday to Friday |
- Public holidays aren't known: they count as working days.
0gives the date itself, even on a Saturday or a Sunday. A DateTime keeps its time of day.
E-mail values
An Email variable, such as the one a mail trigger starts a run with, holds a whole message. Its parts are read with a path, such as {Mail.Subject}, and its attachments are files that any activity that takes a File accepts. Below, Mail is an Email variable. Property names aren't case-sensitive: {Mail.Subject} is {mail.subject}.
| Email property | Type |
|---|---|
| Subject, TextBody, HtmlBody | String |
| From | EmailAddress |
| To, Cc, Bcc, ReplyTo | a list of EmailAddress |
| Attachments | a list of File |
| SentAt, ReceivedAt | DateTime |
| IsRead | Boolean |
| Importance, MessageId, Reference, Protocol, Folder | String |
| EmailAddress property | Holds |
|---|---|
| Address | jane@contoso.com |
| Name | Jane Doe |
| Display | Jane Doe <jane@contoso.com>, or the address alone when there is no name |
| File property | Holds |
|---|---|
| FileName | invoice.pdf |
| Name | invoice: the file name without its extension |
| Extension | .pdf |
| ContentType, Key | texts |
| Size | the size in bytes, an Integer |
| CreatedAt | when the file was downloaded, received or made, a DateTime. Empty for a file stored before Spider recorded it, so use ifNull({Invoice.CreatedAt}, now()). |
What works:
| Expression | Result |
|---|---|
{Mail.From.Address} | jane@contoso.com |
{Mail.From.Display} | Jane Doe <jane@contoso.com> |
any({Mail.To}, "Address", "orders@nidaros.nl") | true when that mailbox is a recipient |
any({Mail.Cc}, "Name", "Finance") | true when Finance is copied |
count({Mail.Attachments}) | how many attachments it has |
any({Mail.Attachments}, "Extension", ".pdf") | true when a PDF is attached |
containsAny(select(filter({Mail.Attachments}, "Extension", ".pdf"), "Name"), select(filter({Mail.Attachments}, "Extension", ".xml"), "Name")) | true when a PDF has an XML of the same name |
join(select({Mail.To}, "Address"), "; ") | the recipients on one line |
gt(daysBetween({Mail.ReceivedAt}, today()), 7) | true more than a week after it arrived |
What doesn't work:
{Mail.To.Address}and{Mail.Attachments.FileName}: a path can't go through a list. Useselect({Mail.To}, "Address")for the addresses, oranyandcountto ask whether, or how many:any({Mail.To}, "Address", "orders@nidaros.nl").join({Mail.To}, "; "): this gives an empty text, because an address is not a text but has properties. Select them first:join(select({Mail.To}, "Address"), "; ").elementAt({Mail.Attachments}, 0).FileName: a path can't go on from a function. Usefirst({Mail.Attachments}, "FileName").contains({Mail.ReceivedAt}, "23:30"): SentAt and ReceivedAt are DateTimes, which the text functions don't search. Compare them as dates,gt({Mail.ReceivedAt}, '2026-10-01 00:00:00'), or write them as text withformatfirst.
Related chapters
- Expressions: how to write an expression, and the builder.
- Types: the types, and which value fits where.