System Variables
Every $(sys.*) value a workflow can reference — execution context, caller data, and date/time — with its type and when it's available.
Alongside the variables your flow sets, every run carries a set of system
variables the platform fills in for you: which workflow is running, who called,
what the current time is. Reference them exactly like your own
variables — $(sys.ctx.conversation_id) — anywhere a field accepts $( ).
System variables are read-only from a Set Variable node — it cannot create or overwrite
anything under sys., the write is rejected.
Two ways to write a reference
$(sys.date.now) and {{sys.date.now}} are equivalent — same grammar, same
result. Use whichever you prefer; the editor's suggestion menu completes
whichever one you start typing. To write a literal delimiter instead of a
reference, escape it with a backslash: \$( or \{{.
Every reference below follows your choice.
Two clocks: sys.date and sys.utc
Date and time come in two namespaces with identical fields. $(sys.date.*) is the
workflow's own timezone, set in workflow settings; $(sys.utc.*) is UTC. A workflow
with no timezone configured falls back to America/New_York.
Within a single node, every date reference is evaluated once, so $(sys.date.minute)
and $(sys.date.second) in the same field can't straddle a tick.
When a variable isn't there
Anything marked Optional depends on how the conversation started — telephony
fields need a phone call, SMS fields need an inbound message, and a carrier may not
supply a caller name at all. An optional value that wasn't supplied resolves to an
empty string when you interpolate it into text, so a message body of $(sys.telephony.ani) renders as nothing at all on a conversation that
didn't start with a phone call. To branch on whether a value was supplied,
use a Condition node's Exists or Does Not Exist operator rather than
relying on the rendered text.
Reference
Execution Context
Identifiers and metadata about the running workflow and conversation.
Always available.
| Reference | Type | Description |
|---|---|---|
| $(sys.ctx.workflow_id) | string | Current workflow ID |
| $(sys.ctx.workflow_instance_id) | string | Current workflow instance ID |
| $(sys.ctx.conversation_id) | string | Current conversation ID |
| $(sys.ctx.organization_id) | string | Current organization ID |
| $(sys.ctx.conversation_type) | string | Channel/type of the current conversation |
| $(sys.ctx.workflow_name) | string | Name of the current workflow |
| $(sys.ctx.version) | string | Version of the current workflow |
| $(sys.ctx.timezone) | string | Timezone of the current workflow |
Telephony
OptionalCaller and dialed-number data supplied by the originating call.
Only when a phone call starts the workflow, and only for the fields the carrier supplies.
| Reference | Type | Description |
|---|---|---|
| $(sys.telephony.ani) | string | Caller number |
| $(sys.telephony.dnis) | string | Dialed number |
| $(sys.telephony.cnam) | string | Caller name |
| $(sys.telephony.callTag) | string | Sharpen call identifier, when the call arrived from Sharpen |
Inbound SMS
OptionalThe message that started the workflow.
Only when an inbound SMS starts the workflow.
| Reference | Type | Description |
|---|---|---|
| $(sys.sms.body) | string | Inbound message text that started the workflow |
| $(sys.sms.from) | string | Sender's phone number |
| $(sys.sms.to) | string | Bandwidth number that received the message |
Web Chat
OptionalThe website visitor and the message that started the workflow.
Only when a chat widget starts the workflow.
| Reference | Type | Description |
|---|---|---|
| $(sys.chat.message) | string | The visitor's first message, which started the workflow |
| $(sys.chat.visitorId) | string | Opaque id for the visitor's browser, stable across their visits |
| $(sys.chat.widgetId) | string | Id of the chat widget the visitor opened |
Caught Error
OptionalWhat failed inside a Try / Catch group.
Only in a Try / Catch group's catch branch. Elsewhere they hold the last catch's values, or nothing at all if no catch has run in this conversation, so an empty sys.error.node does not mean nothing failed. A later catch overwrites them; if that write fails, the earlier catch's values stay in place.
| Reference | Type | Description |
|---|---|---|
| $(sys.error.node) | string | Name of the node inside the group whose outcome was caught |
| $(sys.error.exit) | string | The exit that node took, e.g. fallback or invalidInput; exits like timeout appear only with "Catch every unhandled exit" turned on |
| $(sys.error.message) | string | The failure text the node reported |
Scheduled Run
OptionalFacts about a run that a Schedule Workflow node or agent started.
Only on a run a schedule started.
| Reference | Type | Description |
|---|---|---|
| $(sys.schedule.depth) | number | How many scheduled runs led to this one; absent means 0 |
Date & Time
The current date and time. Every field below is available twice: in the workflow's timezone as $(sys.date.*), and in UTC as $(sys.utc.*).
Always available.
| Reference | Type | Description |
|---|---|---|
| $(sys.date.now), $(sys.utc.now) | string | ISO date-time |
| $(sys.date.day), $(sys.utc.day) | number | Day of month |
| $(sys.date.weekday_num), $(sys.utc.weekday_num) | number | Weekday number (1=Mon) |
| $(sys.date.weekday_long), $(sys.utc.weekday_long) | string | Full weekday name |
| $(sys.date.weekday_short), $(sys.utc.weekday_short) | string | Short weekday name |
| $(sys.date.month), $(sys.utc.month) | number | Month (1-12) |
| $(sys.date.month_long), $(sys.utc.month_long) | string | Full month name |
| $(sys.date.month_short), $(sys.utc.month_short) | string | Short month name |
| $(sys.date.year), $(sys.utc.year) | number | Four-digit year |
| $(sys.date.hour_24), $(sys.utc.hour_24) | number | Hour (0-23) |
| $(sys.date.hour), $(sys.utc.hour) | string | Hour (1-12) |
| $(sys.date.minute), $(sys.utc.minute) | number | Minute (0-59) |
| $(sys.date.second), $(sys.utc.second) | number | Second (0-59) |
| $(sys.date.timezone), $(sys.utc.timezone) | string | Timezone name |
| $(sys.date.offset), $(sys.utc.offset) | number | UTC offset in hours |
| $(sys.date.time_24), $(sys.utc.time_24) | string | 24h time |
| $(sys.date.time), $(sys.utc.time) | string | 12h time |
| $(sys.date.time_long), $(sys.utc.time_long) | string | Long time |
| $(sys.date.time_long_12), $(sys.utc.time_long_12) | string | Long 12h time |
| $(sys.date.date_short), $(sys.utc.date_short) | string | Short date |
| $(sys.date.date_med), $(sys.utc.date_med) | string | Medium date |
| $(sys.date.date_long), $(sys.utc.date_long) | string | Long date |
| $(sys.date.date_huge), $(sys.utc.date_huge) | string | Full date |
| $(sys.date.date_time_short), $(sys.utc.date_time_short) | string | Short date-time |
| $(sys.date.date_time_med), $(sys.utc.date_time_med) | string | Medium date-time |
| $(sys.date.date_time_long), $(sys.utc.date_time_long) | string | Long date-time |
| $(sys.date.date_time_huge), $(sys.utc.date_time_huge) | string | Full date-time |
The other namespaces
sys. is one of five namespaces a reference can name. The other four hold values you set
yourself, and they are read in different places: a workflow node reads its own variables
and $(sys.*), while a voice agent's configuration reads three more.
| Namespace | What it holds | Where it's set | Where it resolves |
|---|---|---|---|
sys. | Call and workflow context the platform fills in for you | The platform | Workflow nodes; in agent configuration, only the subset below |
org.<name> | Organization-wide values shared by every agent | Admin → Secrets & Variables | Voice agent configuration |
secrets.<name> | Organization-wide credentials. Write-only — no API returns a value | Admin → Secrets & Variables | Only in an integration tool's constant parameters and request path, as the request is sent |
agent.<name> | One agent's own values | The agent's Variables section | That agent's configuration |
vars.<name> | Per-call values a workflow hands to an agent | The AI Voice Agent node's Pass to agent list | That agent's configuration, for the call it was passed on |
A workflow node resolves sys. and your own flow variables — and nothing else. org.,
secrets., agent., and vars. all render as an empty string there, with no error. They are
for voice agent configuration.
Full details, and how to create the values, are on Secrets & Variables.
An organization-wide value
Create a variable named brand with the value Northwind Traders, then write an agent's
system prompt against it:
You are the virtual receptionist for {{org.brand}}.Change the variable once and every agent that references it picks up the new value. Nothing needs to be re-saved. Allow up to five minutes for the change to reach every call; When a change takes effect explains why.
A value for one agent
Add a variable named queue with the value Billing in that agent's Variables
section, then reference it in the same agent's prompt:
Transfer to the {{agent.queue}} team when the caller asks about an invoice.An agent. name is visible only to the agent that declares it. Two agents can each have a
queue with different values.
A secret resolves in one place only
A secret is deliberately harder to use than a variable. {{secrets.stripe_key}} is
resolved in one place only — the outbound HTTP request an integration tool makes — so it
may appear only in that tool's constant parameters and its request path. Anywhere else
(a prompt, a greeting, a disposition, an agent variable) is rejected when you save.
That is the point of the design: if a prompt leaks, it leaks the text
{{secrets.stripe_key}} rather than the key.
Only the {{ }} spelling works for a secret. Everywhere else on the platform the two
spellings are interchangeable. A secret is matched as the request leaves, against the exact form
{{secrets.name}}, so a $(secrets.name) is refused rather than resolved. Saving an agent that
references a secret also requires the organization administrator role.
A value for one call
A workflow can hand an agent values that change call to call — a customer id, an account
tier, the result of a lookup it already did — through the AI Voice Agent node's Pass
to agent list. The agent reads them as {{vars.<name>}} in its prompt, greeting,
thinking cue, disposition descriptions, and an integration tool's constant parameters.
Greet the caller by name. Their account tier is {{vars.tier}}.They travel one way. A name the workflow didn't pass reads as empty rather than failing the call, and the values are fixed at the moment of the handover. See Secrets & Variables for the limits.
Functions don't work in agent configuration
{{UPPER(org.brand)}} is valid in a workflow node. In agent configuration, and in an org
variable's value, a function call is rejected — use a plain reference instead.
In a voice agent, only part of sys. resolves
An agent session has no workflow behind it, so the tokens that describe one have nothing
to read. These are the sys. tokens an agent's configuration accepts:
- Context:
$(sys.ctx.conversation_id),$(sys.ctx.organization_id), and$(sys.ctx.agent_id)— the last exists only for agents, which is why it isn't in the reference table above. - Telephony:
$(sys.telephony.ani), the other party's number. On an inbound call that's the caller's number. On an outbound call placed by a Convert to Voice node, it's the number that was dialed, not your caller ID. It is the only telephony field an agent session receives. - Date and time: every
$(sys.utc.*)field.
Everything else is refused when you save the agent, with is not available to a voice agent. That covers $(sys.ctx.workflow_id), $(sys.ctx.workflow_instance_id), $(sys.ctx.workflow_name), $(sys.ctx.version), $(sys.ctx.conversation_type), $(sys.ctx.timezone), all three $(sys.sms.*) fields, $(sys.telephony.dnis), $(sys.telephony.cnam), and every $(sys.date.*) field.
Use $(sys.utc.*) for the time in an agent, not $(sys.date.*). A
workflow reads $(sys.date.*) in the timezone set in its settings, and an agent has
no workflow behind it to supply one, so rather than answer in a zone you did not choose, an
agent refuses the token at save time. UTC is correct without configuration, which is why it is
the one that resolves.