This guide explains the workflow expressions available in Simply CRM for Update fields and related workflow actions that use the same expression engine.
It includes:
-
supported expression syntax
-
available functions
-
practical examples
-
important usage notes
What these expressions are used for
Workflow expressions let a workflow calculate, transform, or retrieve values when it runs.
Typical uses include:
-
filling a field from other fields
-
combining text values
-
calculating dates
-
formatting text
-
applying conditions
-
reading related-record values
-
working with JSON data in advanced workflows
Basic syntax rules
Strings use single quotes
Use:
'Open'
Not:
"Open"
Fields can be referenced directly
Example:
firstname
Expressions can be combined
Example:
concat(firstname, ' ', lastname)
Arithmetic and comparisons are supported
Examples:
amount + 100
quantity * unit_price
amount >= 5000
Conditional logic is supported
Syntax:
if condition then value_if_true else value_if_false end
Example:
if amount > 1000 then 'Large deal' else 'Standard deal' end
Fields from related records can be read directly
Syntax:
(reference_field : (Module) fieldname)
Example:
(account_id : (Accounts) phone)
This reads the phone field from the related Account record referenced by account_id.
Common examples
Use a field value directly
firstname
Returns the value of firstname.
Build a full name
concat(firstname, ' ', lastname)
Example result:
John Smith
Categorize a record by amount
if amount > 1000 then 'Large deal' else 'Standard deal' end
Read a related record field
(account_id : (Accounts) phone)
Returns the related Account phone number.
Supported functions
1. substring(string, start, end)
Returns part of a string.
Example
substring(subject, 0, 10)
Returns the first 10 characters of subject.
Example
substring(accountname, 3, 8)
Returns characters from position 3 to 8.
Note
If used with only 2 parameters, it returns the text from the start position to the end of the string.
2. preg_replace_str_only(pattern, replacement, subject)
Performs a regex replacement on a string.
Example
preg_replace_str_only('/[^0-9]/', '', phone)
Removes all non-numeric characters from a phone number.
Example result
If phone is:
+49 (123) 456-789
Result:
49123456789
3. split(string, separator, index)
Splits a string and returns one part.
Example
split(email, '@', 0)
Returns the part before @.
Example
split(email, '@', 1)
Returns the domain part of the email.
Example result
If email is:
john@example.com
Then:
split(email, '@', 0)
returns:
john
and:
split(email, '@', 1)
returns:
example.com
4. concat(a, b, ...)
Joins multiple values together.
Example
concat(firstname, ' ', lastname)
Result:
John Smith
Example
concat('INV-', invoice_no)
Result:
INV-100045
Note
This function can accept more than two values.
Example:
concat(firstname, ' ', lastname, ' - ', email)
5. time_diff(a, b)
Returns the difference between two date/time values.
Example
time_diff(closingdate, createdtime)
Returns the time difference between closingdate and createdtime.
6. time_diff(a)
Returns the difference between the current date/time and the provided value.
Example
time_diff(duedate)
Useful in advanced date/time calculations.
7. time_diffdays(a, b)
Returns the difference in days between two date/time values.
Example
time_diffdays(closingdate, createdtime)
Returns the number of days between the two dates.
8. time_diffdays(a)
Returns the number of days between now and the provided value.
Example
time_diffdays(duedate)
Useful for overdue or remaining-days logic.
9. add_days(datefield, noofdays)
Adds days to a date.
Example
add_days(closingdate, 7)
Returns a date 7 days after closingdate.
Example
add_days(30)
Returns a date 30 days from today.
Common use
Set a due date 14 days from today:
add_days(14)
10. sub_days(datefield, noofdays)
Subtracts days from a date.
Example
sub_days(closingdate, 3)
Returns a date 3 days before closingdate.
Example
sub_days(10)
Returns the date 10 days before today.
11. add_months(datefield, noofmonths)
Adds months to a date.
Example
add_months(start_date, 1)
Returns a date 1 month after start_date.
Example
add_months(contract_start_date, 12)
Returns the anniversary date one year later.
12. sub_months(datefield, noofmonths)
Subtracts months from a date.
Example
sub_months(contract_end_date, 2)
Returns a date 2 months before contract_end_date.
13. get_date('today')
Returns today’s date.
Example
get_date('today')
14. get_date('tomorrow')
Returns tomorrow’s date.
Example
get_date('tomorrow')
15. get_date('yesterday')
Returns yesterday’s date.
Example
get_date('yesterday')
Common use
Set a field to the current date:
get_date('today')
16. add_time(timefield, minutes)
Adds minutes to a time value.
Example
add_time(time_start, 30)
Returns a time 30 minutes after time_start.
Example
add_time(15)
Returns the current time plus 15 minutes.
17. sub_time(timefield, minutes)
Subtracts minutes from a time value.
Example
sub_time(time_end, 45)
Returns a time 45 minutes before time_end.
18. power(base, exponential)
Raises a number to a power.
Example
power(2, 3)
Returns:
8
Example
power(quantity, 2)
Returns the square of quantity.
19. getDateValue(dateValue, format)
Formats a date/time value.
Example
getDateValue(createdtime, 'd/m/Y')
Formats createdtime as day/month/year.
Example
getDateValue(createdtime, 'l j \of F Y h:i:s A')
Could produce something like:
Monday 4 of March 2026 09:15:22 AM
Example
getDateValue('d/m/Y')
Formats the current date/time using the given format.
Common use
Store a user-friendly date string:
getDateValue(closingdate, 'd.m.Y')
20. str_contains(a, b)
Checks whether two |##|-separated multi-value strings share at least one common value.
Example
str_contains(cf_1234, 'Blue|##|Green')
Returns true if cf_1234 contains either Blue or Green.
Important note
This is not a normal substring search. It is mainly useful for multi-select picklist style values.
Example
If cf_1234 contains:
Red|##|Blue|##|Yellow
then:
str_contains(cf_1234, 'Blue|##|Green')
returns true.
21. RecurrenceRuleAsDates(sourcefield, format, endDate, startDate)
Creates a comma-separated list of dates from a recurrence rule field.
Example
RecurrenceRuleAsDates(recurrence_rule, 'd/m/Y', '31/12/2026', '01/01/2026')
Useful in advanced scheduling or recurrence-based workflows.
22. GetFieldValue(sourcefield)
Returns a field value.
Example
GetFieldValue(firstname)
Returns the value of firstname.
Example with related field
GetFieldValue((account_id : (Accounts) phone))
Returns the phone number from the related Account.
Note
In many simple cases, the field can be used directly without wrapping it in GetFieldValue().
23. GetTime(sourcefield)
Converts a decimal hour value into HH:MM.
Example
GetTime(1.5)
Returns:
01:30
Example
GetTime(hours_worked)
If hours_worked is 2.75, the result would be:
02:45
24. UrlDecode(sourcefield)
URL-decodes a string.
Example
UrlDecode(cf_encoded_text)
If the field contains:
Hello%20World
it returns:
Hello World
25. changeCase(sourcefield, operation)
Changes the letter case of text.
Supported operations:
-
'upper' -
'lower' -
'ucfirst' -
'ucwords'
Example
changeCase(lastname, 'upper')
Result:
SMITH
Example
changeCase(firstname, 'ucfirst')
Result:
John
Example
changeCase(accountname, 'ucwords')
If the value is:
big blue systems
the result is:
Big Blue Systems
Common use
Normalize all-uppercase imports:
changeCase(firstname, 'ucfirst')
26. searchModule(module, field, operator, value, returnFields)
Searches another module and returns matching records as JSON.
Supported operators:
-
'equal' -
'contains' -
'notequal'
Example
searchModule('Contacts', 'email', 'equal', email, '[firstname,lastname,email]')
Searches Contacts where email exactly matches the current record email.
Example
searchModule('Accounts', 'accountname', 'contains', accountname, '[id,accountname,phone]')
Searches Accounts whose account name contains the current record account name.
Note
This is an advanced function, mainly useful for integrations and automation logic.
27. jsonArrayMerge(param1, param2)
Merges two JSON arrays or JSON objects.
Example
jsonArrayMerge('{"a":1}', '{"b":2}')
Result:
{"a":1,"b":2}
Example
jsonArrayMerge(cf_json_part1, cf_json_part2)
Combines two JSON values from fields.
28. json_get(fieldname, key)
Reads a value from JSON using a key path.
Example
json_get(cf_json_payload, 'customer.name')
Returns the nested value of customer.name.
Example
json_get(cf_json_payload, 'items[0].sku')
Returns the sku of the first item in the items array.
Example
If cf_json_payload contains:
{"customer":{"name":"John"}}
then:
json_get(cf_json_payload, 'customer.name')
returns:
John
29. json_set(fieldname, key, value)
Sets or updates a value in JSON.
Example
json_set(cf_json_payload, 'customer.name', firstname)
Updates customer.name using the current record firstname.
Example
json_set(cf_json_payload, 'status', 'Processed')
Sets the top-level status value to Processed.
Example
If cf_json_payload contains:
{"status":"New"}
then:
json_set(cf_json_payload, 'status', 'Processed')
returns updated JSON similar to:
{"status":"Processed"}
30. json_get_line_items(recordId)
Returns line items from an inventory record as JSON.
Example
json_get_line_items(id)
Useful in modules such as:
-
Quotes
-
Sales Orders
-
Purchase Orders
-
Invoices
This is mainly for advanced integrations or JSON transformations.
31. getfieldOptions(Module.fieldname)
Returns the available picklist options for a field as JSON.
Example
getfieldOptions('HelpDesk.ticketstatus')
Returns the available values for the ticketstatus field in HelpDesk.
Note
This is mostly useful in advanced workflows or integrations.
Arithmetic operators
These operators can be used directly in expressions.
Addition
amount + 100
Adds 100 to amount.
Subtraction
amount - discount_amount
Subtracts discount_amount from amount.
Multiplication
quantity * unit_price
Calculates the total from quantity and unit price.
Division
amount / 2
Divides amount by 2.
Comparison operators
These operators can be used inside conditions.
Equal
amount == 1000
Greater than
amount > 0
Less than
amount < 0
Greater than or equal
amount >= 500
Less than or equal
amount <= 2000
Conditional expressions
The expression engine supports if / then / else / end.
Basic example
if bill_country == 'Denmark' then 'DK' else 'Other' end
Another example
if amount >= 10000 then 'Enterprise' else 'SMB' end
Nested example
if amount > 10000 then 'Large' else if amount > 5000 then 'Medium' else 'Small' end
Use nested conditions carefully to keep expressions readable.
Related field syntax
A field from a related record can be read using:
(reference_field : (Module) fieldname)
Example
(contact_id : (Contacts) email)
Returns the email of the related Contact.
Example
(account_id : (Accounts) phone)
Returns the phone number of the related Account.
Practical use
Fill a field on the current record with a value from a linked Account:
(account_id : (Accounts) website)
Practical examples
1. Build a full name
concat(firstname, ' ', lastname)
2. Create a due date 14 days from today
add_days(14)
3. Create a due date 7 days after another date
add_days(closingdate, 7)
4. Convert text to uppercase
changeCase(lastname, 'upper')
5. Capitalize a first name
changeCase(firstname, 'ucfirst')
6. Extract an email domain
split(email, '@', 1)
If email is john@example.com, the result is:
example.com
7. Strip formatting from a phone number
preg_replace_str_only('/[^0-9]/', '', phone)
8. Categorize a deal by amount
if amount >= 10000 then 'Enterprise' else 'SMB' end
9. Pull a related Account phone number
(account_id : (Accounts) phone)
10. Read a value from JSON
json_get(cf_api_response, 'data.customer_id')
11. Format a date for display
getDateValue(closingdate, 'd.m.Y')
12. Prefix a reference number
concat('CASE-', ticket_no)
Important notes
1. Always use single quotes for text
Correct:
'Closed Won'
Incorrect:
"Closed Won"
2. concat() can take multiple parts
Example:
concat(firstname, ' ', lastname, ' (', email, ')')
3. str_contains() is for multi-value strings
It checks overlap in values separated by |##|, not ordinary text search.
4. Some functions are advanced
These are typically used in more advanced workflows or integrations:
-
searchModule() -
jsonArrayMerge() -
json_get() -
json_set() -
json_get_line_items() -
getfieldOptions() -
RecurrenceRuleAsDates()
5. Related-record syntax is especially useful
Example:
(account_id : (Accounts) phone)
This makes it possible to pull values directly from linked records without custom code.
Quick reference
Text functions
-
substring() -
preg_replace_str_only() -
split() -
concat() -
UrlDecode() -
changeCase()
Date and time functions
-
time_diff() -
time_diffdays() -
add_days() -
sub_days() -
add_months() -
sub_months() -
get_date() -
add_time() -
sub_time() -
getDateValue() -
GetTime()
Logic and numeric functions
-
power() -
if / then / else / end -
arithmetic operators
-
comparison operators
Related-record access
-
(reference_field : (Module) fieldname) -
GetFieldValue()
JSON and advanced functions
-
searchModule() -
jsonArrayMerge() -
json_get() -
json_set() -
json_get_line_items() -
getfieldOptions() -
RecurrenceRuleAsDates()
Summary
These workflow expressions support:
-
field-based calculations
-
text formatting
-
date arithmetic
-
conditional logic
-
related-record lookups
-
JSON transformation
-
module search functions
Most commonly used expressions include:
-
concat() -
changeCase() -
split() -
add_days() -
get_date() -
if ... then ... else ... end -
related-record syntax such as
(account_id : (Accounts) phone)