Variables & Data
Storing data, referencing it with $(name), querying databases, and calling integrations.
Variables are how a flow carries data from one step to the next: a caller's input, a value looked up in a database, a field from an API response. They're scoped to the conversation and can be read by any node downstream of where they're set. See Scope for what "the conversation" covers when a call passes through more than one workflow.
The $(name) syntax
Reference a variable anywhere a field accepts it by wrapping its name in
$(...). When the node runs, $(name) is replaced with the variable's current
value.
For example, if a variable customerName holds "Alex", a Send SMS body of:
Hi $(customerName), thanks for calling!is sent as Hi Alex, thanks for calling!. You can reference several variables
in one field, and combine them with literal text.
A variable must be set before it's read. Referencing $(name) on a path where that variable
was never assigned yields no value. Order your flow so the node that sets a variable runs before
the nodes that use it.
Setting variables
Use a Set Variable node to create or update variables during a run. Beyond plain assignment, Set Variable can compute a value with built-in operations, so you can derive a value once and reuse it instead of recomputing it in several places:
- Arithmetic — add, subtract, multiply, divide, round, min/max, and more.
- String — append, prepend, length, slice, and find-and-replace (including regex replace).
- Date — create, format, diff, and read or set parts of a date/time.
- JSONPath — extract a value from a JSON structure held in a variable.
The inputs to these operations can themselves be $(name) references, so you can
build a value from other variables.
Patterns Regex Replace refuses
Regex Replace and Regex Replace All refuse a pattern whose matching time can grow
exponentially with the input. A pattern is refused when it has a group repeated by +, *,
or a brace quantifier that allows more than one repetition ({2}, {2,}, {1,5}), and that
group either:
- contains
+,*,?, or a variable-count brace such as{1,3}or{2,}, at any depth, or - has two alternatives that can start with the same character. An alternative that starts with a character class, a group, or something that can match nothing counts as starting with any character.
| Pattern | Result |
|---|---|
(a|aa)+ | Refused |
(\d+)+ | Refused |
(ab|cd)+ | Accepted |
\d{1,3}(,\d{3})* | Accepted |
(\.\d+)? | Accepted |
The check errs toward refusing. Some safe patterns are refused, for example (\d|\s)+ and
((ab)|(cd))+. Rewrite one as a character class ([\d\s]+) or without the inner groups
((ab|cd)+).
The check runs when the node runs, not when you save. A workflow with a refused pattern
saves and publishes normally. When the node runs, it takes its fallback exit and sets
none of its variables, including the ones that did not use the pattern.
Scope
A conversation has one set of variables, shared by everything that handles it. A call that starts in one workflow, hands off to an AI agent, and has that agent invoke a second workflow uses the same set throughout: what the first workflow set, the agent's tools and the second workflow can read.
That is what makes context carry across a hand-off, and it has one consequence worth designing around. Two workflows that write the same variable name overwrite each other. The later write wins, and neither one is told. Variables with different names never collide, so the fix is a naming convention rather than avoiding shared variables.
If a workflow is meant to be reusable across calls that already carry data, prefix its own working
values with something specific to it — refund_step, not step.
Variables do not outlive the conversation, and two conversations never see each other's.
System variables
Every run also carries values the platform fills in itself: the conversation's id,
the caller's number, the current date and time. They live under the sys. prefix and
are referenced the same way:
Thanks for calling from $(sys.telephony.ani).You can't set or overwrite them; a Set Variable node writing to a sys. name is
rejected. See the system variable reference for
every available token, its type, and when it's present.
Getting data from a database
SharpenDB nodes read and write records directly (requires the Sharpen integration):
- SELECT reads rows; capture the columns you need into variables.
- INSERT, UPDATE, and DELETE modify rows.
SELECT (and the other operations) save results into variables by JSONPath, so
a value returned by a query becomes available to later nodes as $(name). See
the node reference for each node's fields and exits.
Getting data from an integration
Integration and Invoke Lambda nodes call external services and, like the
database nodes, capture fields from the JSON response into variables by JSONPath.
That response data is then usable downstream with $(name) — for instance,
branch on it in a Condition or include it in a message.
Nodes that call out (database, integration, Lambda) expose a timeout exit. Wire it so the flow
still behaves sensibly when a call is slow or fails — see Error
Handling.