> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.meetgail.com/platform/workflows/core-concepts/expressions/function-reference/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.meetgail.com/_mcp/server. # Function Reference > The functions you can call inside an expression, from text checks to phone-number formatting. Beyond arithmetic and comparisons, an [expression](/platform/workflows/core-concepts/expressions/using-expressions-in-nodes) can call functions to do more: count a list, check whether text contains a word, keep only the items that match a rule, or format a phone number. This page lists the functions commonly available. The builder also offers a function picker, which is the authoritative, up-to-date list while you are editing an expression. Functions come in two flavors. **Standard functions** are the general-purpose tools that come with the expression language. **Custom functions** are extras built specifically for Gail workflows, like formatting a phone number. ## How functions are written A function name is followed by its inputs in parentheses. Some functions are written after the value they act on, joined by a dot, which reads naturally: ```text size(node.items.list) "hello world".contains("world") ``` Function names use camelCase (for example `startsWith`, `endsWith`), while the values you reference use lowercase names with underscores (for example `node.contact_phone`). The two styles sit together cleanly, so `normalizePhoneNumber(node.contact_phone)` reads without confusion. ## Standard functions A selection of the general-purpose functions you will reach for most often: | Function | What it does | Example | | ------------ | ----------------------------------------------------- | --------------------------------------- | | `size` | Counts the items in a list, or the characters in text | `size(node.contacts.list)` | | `contains` | Checks whether text contains a smaller piece of text | `node.subject.value.contains("urgent")` | | `startsWith` | Checks whether text begins with a given piece | `node.code.value.startsWith("POL-")` | | `endsWith` | Checks whether text ends with a given piece | `node.file.name.endsWith(".pdf")` | | `matches` | Checks whether text fits a pattern | `node.email.value.matches(".+@.+")` | | `map` | Builds a new list by transforming each item | `node.quotes.list.map(q, q.premium)` | | `filter` | Keeps only the items that pass a test | `node.amounts.list.filter(n, n > 0)` | | `int` | Turns a value into a whole number | `int(node.count.value)` | | `string` | Turns a value into text | `string(node.total.value)` | With `map` and `filter`, the first name in the parentheses (like `q` or `n`) stands for the current item as the function walks the list. ```text [1, 2, 3, 4].filter(n, n % 2 == 0) // keeps 2 and 4 ``` ## Custom functions ### normalizePhoneNumber Formats a phone number into the standard international format (like `+442083661177`). Give it the number and a two-letter country code so it knows how to read a local number. ```text normalizePhoneNumber("020 8366 1177", "GB") // "+442083661177" ``` This is handy for tidying up phone numbers before you store them or pass them to a call or messaging step, so they are all in a consistent shape. The number has to belong to the country code you give. A number already written with a leading `+` for a different country fails rather than coming back unchanged, so `normalizePhoneNumber("+447700900123", "US")` is an error. #### Falling back instead of failing Add a third input to get a fallback value back for a number that cannot be read, instead of stopping the run: ```text normalizePhoneNumber("notaphone", "US") // error, the run stops normalizePhoneNumber("notaphone", "US", "") // "" ``` This matters most when you tidy a whole list at once, for example every phone number in an uploaded contact file with a [Map](/platform/workflows/node-reference/logic-and-flow/map). Without a fallback, one bad number fails the entire list. With one, the bad rows come out as the fallback value and you can filter them out in a later step. An empty text `""` is a good choice, because a real formatted number is never empty. Only the number falls back. A country code that is not valid still fails, because that is a mistake in the workflow rather than in the data. ### replace Replaces every occurrence of one piece of text with another. Give it a count as a third input to replace only the first few, left to right. ```text "hello world".replace("o", "0") // "hell0 w0rld" "o-o-o-o".replace("o", "X", 2) // "X-X-o-o" ``` Replacing with empty text removes the piece, which is the usual way to clean up a value before sending it somewhere: ```text "(954) 552-7023".replace(" ", "").replace("(", "").replace(")", "").replace("-", "") // "9545527023" ``` The text to look for cannot be empty. ### regexReplace Replaces every match of a pattern, for clean-ups that a plain `replace` cannot express in one step. Use `$1`, `$2`, and so on in the replacement to put back part of what the pattern matched: ```text "o-o-o".regexReplace("o", "X") // "X-X-X" "+15551234567".regexReplace("^\\+1(.*)$", "$1") // "5551234567" ``` To write a literal dollar sign in the replacement, write it twice: `$$`. Most pattern features work: character classes, `\s`, `\d`, `\b`, alternation, anchors, and quantifiers. Look-ahead, look-behind, and back-references are not supported, and a pattern that uses them fails with an error that names the unsupported part. ### first and last Return the first or last item of a list, without writing the list's name twice to work out its position: ```text [1, 2, 3].first() // 1 [1, 2, 3].last() // 3 node.http_request.response_body.last().id // the id of the final item ``` The item comes back as it is, so you can keep reading fields from it, as with `.id` above. > **Note** > > `first` and `last` fail on an empty list. If a list can be empty, check its size > first: `size(node.quotes.list) > 0 ? node.quotes.list.last().id : ""`. Do not > compare the result to `null` instead - that check does not work here. > **Note** > > If a function is given something it cannot handle, such as a phone number it > cannot make sense of, the expression fails and the run stops with an error. > Feed functions values you expect to be valid, and use a > [Conditional](/platform/workflows/node-reference/logic-and-flow/conditional) or > [Check](/platform/workflows/node-reference/logic-and-flow/check) earlier if you need to > guard against bad input. ## Related #### [Expressions](/platform/workflows/core-concepts/expressions/using-expressions-in-nodes) The formulas that these functions plug into. #### [String Templates](/platform/workflows/core-concepts/expressions/string-templates) Use a function's result inside text like an email body. > Documentation for Gail, the AI platform for financial services. Learn how to set up GailGPT and Gail Agent to automate customer communications for insurance, banking, and finance.