Skip to content

Expressions

Expressions are how you compute values inside a spec. Anywhere an operation expects a value — an external_id, a condition for if_else, the items to loop over in for_each — you reach for an expression. They're the spec language's verbs for getting values, the way operations are its verbs for doing things.

Most expressions take other expressions as arguments — that's how you build up a value step by step (e.g. an if_else's condition might be an equals whose left side is a var reference and right side is a literal).

This page covers all of them, grouped by what they're for:

  • Literal & variableliteral, var
  • Logicand, or, not, equals, equals_one_off, greater_than, is_null, is_empty, exists
  • Stringsconcat, implode_with_spaces, string_between, string_contains, string_replace
  • Numberssum, multiply, divide, minimum
  • Datesparse_datetime, parse_timestamp, datetime_difference

Literal and variable

These two are the foundation: every other expression eventually bottoms out in a literal value or a variable lookup.

literal

Use this when you want to put a fixed value directly into the spec — a string like "Deal | won", a number like 1.21, a hard-coded ID. The Spec Builder accepts whatever type you type in.

valueoptionalany

The literal value. Strings, numbers, and booleans are all accepted.

var

Use this to read the value of a variable currently in scope — a field on the source model, an enrichment, a constant, the result of an earlier return_as, or the iteration item inside a for_each body. Variable picker autocompletes from the scope panel.

varrequiredvariable path

The dotted path to the variable. Examples: source_model.id, event.ghl_opportunity.assignedTo, agent_external_identity.id.

Logic

Boolean expressions used in if_else conditions and combined with and / or / not to express richer conditions.

and

Use this when several conditions all need to be true. Short-circuits — stops checking the rest as soon as one argument is false.

argumentsrequiredlist of booleans

The conditions to evaluate. Returns true only if every one is true.

or

Use this when at least one of several conditions needs to be true. Short-circuits — stops checking the rest as soon as one argument is true.

argumentsrequiredlist of booleans

The conditions to evaluate. Returns true if at least one is true.

not

Use this to flip a boolean — useful for "if X is not true, then..." conditions.

expressionrequiredboolean

The boolean to negate.

equals

Use this to compare two values for equality. Works for strings, numbers, and other comparable values; comparisons are loose (string "5" and number 5 are equal).

leftrequiredany
rightrequiredany

equals_one_off

Use this when you want to check whether a value matches any of several alternatives — like a multi-way equality check without writing a chain of or + equals.

needlerequiredany

The value you're looking for.

haystackrequiredlist

The values to check against. Returns true if needle matches any of them.

A note on the name

The identifier is equals_one_off (with the extra "f"). It's a typo from when the expression was first added, but specs in production already use it under that name, so renaming would break them. The label in the inspector reads "Equals One Of" — that's how it's pronounced.

greater_than

Use this to check whether one number is strictly greater than another. For "greater than or equal," combine with equals using or.

leftrequirednumber
rightrequirednumber

is_null

Use this to check whether a variable's value is null — typically as a guard before reading a field that the source might not always populate.

varrequiredvariable path

The variable to check. Returns true if its value is null.

is_empty

Use this to check whether a variable is "empty" in the everyday sense — null, empty string, zero, empty array. Useful for guarding a branch that should only run when there's actually a value to act on.

varrequiredvariable path

The variable to check. Returns true if its value is null, empty, or zero.

exists

Use this to check whether a variable is even in scope at this point in the spec — different from is_null, which assumes the variable exists and asks whether its value is null. Useful when an enrichment is optional and you need to skip the branch entirely if the field wasn't loaded.

varrequiredvariable path

The variable to check. Returns true if a variable with this path is currently in scope.

Example: matching a custom field by ID and value

Inside a for_each over a contact's custom fields, you want to react only when one specific field has a specific value. The condition uses and to combine two equals comparisons:

  • leftequals(field.id, "XlG7djKG0BdlUx2njBZa")
  • rightequals(field.value, "Ja")

Wrapped in an if_else, this gives you a single branch that runs only when the named custom field is set to "Ja" — used in the GHL stage-change processor to detect Setter-handled deals.

Strings

For building IDs, types, and any text the spec needs to compose from pieces.

concat

Use this when you want to glue several values together end to end into a single string — typically for building composite IDs that look like <a> | <b> or <prefix><value>. If you want a separator, include it as one of the arguments (a literal " | " is the standard).

argumentsrequiredlist of strings or numbers

The values to join, in order. They're concatenated with no separator.

implode_with_spaces

Use this when you want to glue several values together with single spaces between them — useful for building human-readable strings like a person's full name from first + last. Empty/null arguments get skipped, so you don't end up with double spaces or trailing whitespace.

argumentsrequiredlist of strings or numbers

The values to join. Joined with a single space; nulls and empty strings are dropped.

string_between

Use this to extract the text between two markers in a string. Useful for parsing a value out of a free-form string the source delivers — for example pulling an order number out of "Order #1234 confirmed".

subjectrequiredstring

The string to search in.

fromrequiredstring

The marker the wanted text starts after.

torequiredstring

The marker the wanted text ends before.

If either marker isn't found in the subject, the expression returns null.

string_contains

Use this to check whether a string contains another string anywhere inside it. Case-insensitive.

subjectrequiredstring

The string to search in.

searchrequiredstring

The substring to look for.

string_replace

Use this to replace every occurrence of one substring with another — or to strip a substring entirely by leaving the replacement empty. Used in the production specs to clean up source data, like stripping quotes from a date string before parsing it.

subjectrequiredstring

The string to operate on.

searchrequiredstring

The substring to find.

replaceoptionalstring

The replacement. If left empty, every match of search is removed.

Example: stripping multiple characters

Source data sometimes arrives with stray quotes around values — "'2026-01-15'" instead of 2026-01-15. Two string_replace calls nested together (one stripping ', one stripping ") clean it up before parsing:

  • The outer string_replace has subject = an inner string_replace
  • The inner string_replace has subject = payload.Date, search = ', replace = empty
  • The outer one has search = ", replace = empty

The result lands in a define_variable named date, which the rest of the spec then uses freely. Pattern from the Google Ad Spend processor.

Numbers

Arithmetic for sums, totals, and conversions.

sum

Use this to add numbers together. Common case: accumulating a running total inside a for_each loop, with the previous total and the new value as arguments.

argumentsrequiredlist of numbers

The numbers to add. Empty list returns 0.

multiply

Use this to multiply numbers together. Common case: applying a VAT factor to a unit price × quantity (multiply(1.21, line.price, line.quantity)).

argumentsrequiredlist of numbers

The numbers to multiply. Empty list returns null.

divide

Use this to divide one number by another — for example computing an average, or converting between units. Returns null if the denominator is 0 (or if either side is missing) so you don't get an error mid-spec.

numeratorrequirednumber
denominatorrequirednumber

minimum

Use this to take the smaller of several numbers. The production specs use this as a cap — for example, capping a sale's total value at 1 000 000 to keep one outlier from skewing every chart.

argumentsrequiredlist of numbers

The numbers to compare. Returns the smallest.

Example: line totals with VAT

A line on an order has a quantity and a price, both excluding VAT. The line's contribution to the running total is computed with one multiply:

  • arguments1.21 (literal), line.quantity, line.price

The result is the VAT-inclusive line total. Wrapping that whole expression in a sum together with the running total gives you the new running total — that's the inner accumulation step in the Troublefree offer processor.

Dates

Source systems hand you dates as strings or numeric timestamps. These expressions turn them into proper datetime values that operations like upsert_activity and if_else (with a greater_than) can work with.

parse_datetime

Use this when your source field is a date or datetime string — anything Carbon can parse, like "2026-01-15T14:32:00Z", "2026-01-15", or "15-01-2026 14:32". The result lands in your tenant's timezone.

datetimerequiredstring

The string to parse.

If the string is just a date with no time, the time defaults to 06:00 (so daily activities don't all stack on midnight, which causes off-by-one display issues in Amsterdam time).

parse_timestamp

Use this when your source field is a numeric Unix timestamp — typically the case with APIs that return milliseconds since epoch (GoHighLevel, for example). Auto-detects whether the value is in seconds, milliseconds, or microseconds.

timestamprequiredstring or number

The Unix timestamp. Whatever unit it's in, this expression figures it out.

datetime_difference

Use this to compute the time between two datetimes. Returns the difference in seconds — multiply if you need a different unit.

startrequireddatetime
endrequireddatetime

Returns 0 if either side is null.