Variables
A variable is a path between double braces that SquadOS replaces with a run’s value. For example, Hi, {{contact.first_name}}! may become Hi, Marina!.
The value is resolved when the step runs, not when you save the flow. Two runs of the same version may therefore produce different text.
Where to use them
Section titled “Where to use them”The editor offers Insert variable in compatible fields. The picker appears in:
- the instruction in Analyze with AI;
- Send message text and WhatsApp template values;
- the subject and body in Send email;
- the title in Get the contact’s conversation;
- the instruction in Hand off to agent;
- the value in Save to contact;
- the URL, header values and body in Call webhook;
- both sides of each comparison in Condition.
In Pick contact by identity, the runtime also interpolates the value, but this field does not show the picker. If needed, type a complete valid path such as {{contact.identity_value}}.
The picker is contextual: it shows the recommended list for that point in the flow. Recognized variables are highlighted; a variable the editor does not recognize turns red. Red is an important warning, but it does not currently guarantee publication will be blocked: an unknown field inside an available namespace may pass and become blank at run time. Do not publish while any variable is red.
Conversation variables
Section titled “Conversation variables”They appear when every path reaching the step provides a conversation.
| Variable | Value |
|---|---|
conversation.transcript | up to the 50 most recent messages, in chronological order, one line per message as role: content |
conversation.status | technical state: active, completed or failed |
conversation.inbox_id | inbox ID |
conversation.agent_id | associated AI agent ID |
conversation.assigned_to | responsible person’s ID |
conversation.channel_source | technical channel source |
The full history may contain more than 50 messages. conversation.transcript keeps only the 50 most recent; do not use it as a complete archive or assume the beginning of the conversation is present.
The runtime also recognizes conversation.id and conversation.ai_enabled, although the current picker does not show them. Because this difference may change, prefer paths offered by the interface and test any manual use before activation.
Contact variables
Section titled “Contact variables”| Variable | Value |
|---|---|
contact.first_name | first whitespace-separated part of display_name |
contact.display_name | name as received from the channel or record |
contact.identity_value | the contact’s phone, email, username or other identifier |
contact.metadata | JSON object containing custom fields |
Append a key to read a custom field: {{contact.metadata.city}}. metadata is an open object; the picker does not list each key, so you must type it.
contact.first_name is not stored as a separate field. It is derived from the first part of display_name. If the contact has no name, the result may be blank; if the received name is a phone number or email, that value may appear instead. For a safe greeting, keep fixed text that still works without the variable.
The runtime also recognizes contact.id, contact.identity_type and contact.outbound_opt_out_at, but the picker does not offer them.
Trigger data
Section titled “Trigger data”The namespace is trigger.payload.
For the Contact added to list trigger, the picker offers:
| Variable | Value |
|---|---|
trigger.payload.list_name | list name |
trigger.payload.list_id | list ID |
trigger.payload.consent_source | consent source received in the event |
For the Schedule trigger, the real payload contains trigger.payload.scheduled_for and trigger.payload.fired_at. The picker incorrectly shows the three list fields; type the schedule paths manually if you need them. The other triggers do not promise dedicated payload fields.
Objects inside trigger.payload can also be accessed with dot notation, provided the event actually supplies that structure.
Analyze with AI output
Section titled “Analyze with AI output”Each field declared in Analyze with AI becomes a variable after the step finishes. Its path combines the node ID and field name, for example {{n5.buying_intent}}.
The output does not exist in the producing step itself or above it. It only appears in downstream steps that the analysis necessarily reaches.
What each path provides
Section titled “What each path provides”| Trigger | Conversation | Contact | Useful trigger.payload |
|---|---|---|---|
| Conversation event | yes | yes | not documented |
| Idle conversation | yes | yes | not documented |
| Contact tag | no | yes | not documented |
| Contact added to list | no | yes | list and consent |
| Schedule | no | no | run timestamps |
| Audience | no | yes | not documented |
Pick contact starts providing a contact only to the steps below it. Get the contact’s conversation requires a contact and starts providing a conversation only below it.
When paths converge, the intersection applies: the step receives only what every previous path guarantees. If Conversation event and Contact tag reach the same step, both provide a contact, but only one provides a conversation; conversation variables are therefore unavailable after the join. Put Get the contact’s conversation in the path that starts without a conversation, or keep the branches separate.
Publication blocks an absent namespace or an AI output that is not upstream. It validates namespace availability, however, not the catalog of internal fields. {{conversation.status}} is rejected where there is no conversation, but {{conversation.unknown_field}} may be accepted where a conversation exists and resolve to blank.
Blank values, objects and syntax
Section titled “Blank values, objects and syntax”- a missing or null value becomes blank text;
- a number or boolean becomes text;
- an object or array becomes JSON;
- whitespace inside the braces is accepted, as in
{{ contact.display_name }}; - paths accept letters, numbers, underscores and dots;
- an unfinished brace, a hyphen in the path or another unrecognized form may remain literally in the text.
If an entire message or email subject becomes blank after interpolation, that run fails with a configuration alert. Five consecutive failures of the same kind in the same step deactivate the automation; a successful run before then ends the sequence. Correct the value, save and reactivate the automation when needed.
Prefer a textual fallback: Hello! is safe; only {{contact.first_name}} is not. For conditional logic, check the variable with is empty before sending.
Verify before activation
Section titled “Verify before activation”- Use the picker whenever it offers the path.
- Remove every red marker even if the flow still allows saving.
- Confirm that every path to the step provides the same context.
- Test a contact with no name and a missing metadata field.
- For schedules, type
scheduled_fororfired_atwith thetrigger.payloadprefix. - Check Activity after the first real runs.
The test uses the steps’ real execution, subject to the limits described for each action. In particular, the Contact added to list test does not currently populate the trigger’s list data. Do not treat a blank field in that simulation as proof that the real event will also be blank.