Skip to content

Variables

A variable is a path between double braces that SquadOS replaces with a run’s value. For example, Hi, {{nome}}! 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.

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 and Send campaign;
  • the text in Add private note;
  • 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.

They appear when every path reaching the step provides a conversation.

VariableValue
conversation.transcriptup to the 50 most recent messages, in chronological order, one line per message as role: content
conversation.statustechnical state: active, completed or failed
conversation.inbox_idinbox ID
conversation.agent_idassociated AI agent ID
conversation.assigned_toresponsible person’s ID
conversation.channel_sourcetechnical 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.

VariableValue
nomethe contact’s first name, with letter case tidied
nome_completothe contact’s full name, with letter case tidied
contact.phonephone number on the contact record
contact.emailemail on the contact record
contact.identity_valuephone, email, username or other identifier, depending on the channel
contact.identity_typechannel of the contact’s identity
contact.metadataJSON 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.

{{nome}} and {{nome_completo}} are the only variables without a prefix, and they keep these names in every language; they are meant to go inside a sentence. {{nome}} is the first whitespace-separated part of the contact’s name. In both, a name written entirely in uppercase or lowercase, such as MARIA DA SILVA, comes out as Maria da Silva; mixed-case names such as McDonald stay as they are.

The older forms still work: {{contact.first_name}} is equivalent to {{nome}}, with the same case adjustment. {{contact.display_name}} returns the name exactly as stored, with no adjustment — use it in webhooks, conditions, or field writes, where the original data matters.

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 and contact.outbound_opt_out_at, but the picker does not offer them.

The namespace is trigger.payload.

For the Contact added to list trigger, the picker offers:

VariableValue
trigger.payload.list_namelist name
trigger.payload.list_idlist ID
trigger.payload.consent_sourceconsent source received in the event

For the Schedule trigger, the picker offers trigger.payload.scheduled_for (planned time) and trigger.payload.fired_at (time when the engine began the occurrence). For the Command trigger, it offers trigger.payload.invoked_by_name (who pressed the button) and trigger.payload.label (the button name). When two triggers reach the same step, the picker combines each one’s fields. 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.

Each new Analyze with AI returns a single variable after success. Its path combines the node ID and Variable name, for example {{n5.buying_intent}}. The single-result format is published in Dev; its production release is still pending. Legacy nodes retain their existing fields and variables.

The value may be text, an option’s name, true/false, or a score. For scores, the variable keeps its fractional value even when the canvas output is rounded: {{n5.score}} may contain 7.3 while the flow follows output 7. The selected path and model/usage details shown in Activity do not create additional variables.

The output does not exist in the producing step itself or above it. It only appears in downstream steps that the analysis necessarily reaches.

After a Call webhook step, later steps receive {{<step id>.status}} (HTTP code), {{<step id>.body}} (response text, up to 4,000 characters), and {{<step id>.json}}. To read a field of the JSON response, go down with dots, including list indexes: {{n5.json.customer.name}}, {{n5.json.items.0.id}}.

json is an open object: the editor does not mark an unknown field in red, and a missing field becomes blank. After a successful Test call, the picker lists the fields of the real response with the values received, which avoids typing wrong paths.

TriggerConversationContactUseful trigger.payload
Conversation eventyesyesnot documented
No reply on conversationyesyesnot documented
Commandyesyeswho pressed and button name
Contact tagnoyesnot documented
Contact added to listnoyeslist and consent
Schedulenonorun timestamps
Audiencenoyesnot 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. For single-result analyses, it also requires the exact configured variable name: update references in following steps when renaming it. Internal fields in other groups do not have the same validation: {{conversation.status}} is rejected where there is no conversation, but {{conversation.unknown_field}} may be accepted where a conversation exists and resolve to blank.

  • 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 {{nome}} is not. For conditional logic, check the variable with is empty before sending.

  1. Use the picker whenever it offers the path.
  2. Remove every red marker even if the flow still allows saving.
  3. Confirm that every path to the step provides the same context.
  4. Test a contact with no name and a missing metadata field.
  5. For schedules, use scheduled_for or fired_at from the picker, with the trigger.payload prefix.
  6. 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.