Skip to main content
A variable is a token like {{first_name}} that DMLY replaces with the real value per contact at the moment a message sends. In the flow builder, any field that takes them has a {} picker listing the common ones, but the picker is a convenience, not the boundary: tokens are plain text, and everything on this page works typed by hand.

The three rules

1. An unresolvable token becomes empty text. A message never reaches a contact with a literal {{order.number}} showing, but it can arrive with a hole where the value should have been: “Your order is on its way”. The builder’s canvas preview is the opposite: it shows unknown tokens as typed, so a clean-looking preview is not proof the token will resolve. Test by triggering the flow for real. 2. Most tokens are scoped to an event. Contact tokens always work. Everything dotted ({{invoice.number}}, {{appointment.date}}, {{order.total}}) carries data only when the flow started from the matching event, or after a step that fetched it (a Find Order step fills the order tokens, a Book Meeting step fills the meeting.* ones). An {{invoice.number}} in a plain keyword-reply flow resolves to nothing, every time. 3. Only flows get the full set. The event-scoped tokens are a flow-builder feature. Quick automations, broadcasts, sequences and Bot Setup replies substitute contact-level tokens only: the Contact, Business and System tables below (all but {{flow_run_id}}, which needs a flow), plus the two live balances. A {{cart.total}} in a quick automation’s reply is empty even though the trigger matched a cart.
Condition steps take no variables at all. A condition’s value box compares literal text; it has its own dropdowns for reading trigger data, so don’t type {{tokens}} there.

Contact

Always available, everywhere variables work.
The picker’s Custom field… entry inserts the placeholder {{custom.field}} literally. Replace field with your real field name ({{custom.membership_tier}}), or the token resolves against a field actually called “field”, which is almost certainly empty.

Business

System

The picker’s System group: facts about the conversation rather than about the person. Seven of the eight work everywhere variables work, like the Contact tokens; only {{flow_run_id}} needs a flow. These are what you write into a spreadsheet row or an HTTP Request body when the row has to be matched back to DMLY afterwards, because a name, phone number or username can be missing today and different tomorrow, and an id can’t.
{{last_message}} outside a flow is a preview, not a promise. In a broadcast, a sequence step or a notification there is no run to read from, so it falls back to the conversation’s stored last message, which DMLY also updates when you send. Mid-conversation it can just as easily be your own last reply as the customer’s.
If a flow saves a variable of its own under one of these names, through an HTTP Request step or a Get row from Google Sheets step, your value wins and the system one is not used.

Live balances

These two query the contact’s balance at the moment the message sends, in any flow, with no event scope.

Appointments

Filled in flows started by an appointment event (booked, confirmed, rescheduled, and the rest). Dates and times are rendered in the contact’s timezone, so “10:00 AM” is their 10 AM. The meeting.* spellings ({{meeting.type}}, {{meeting.date}}, {{meeting.time}}, {{meeting.datetime}}, {{meeting.link}}, {{meeting.location}}, {{meeting.duration}}, {{meeting.reschedule_url}}, {{meeting.cancel_url}}) are the original family. {{appointment.*}} are aliases of them, plus a few extras (service, staff, status) that only appointment events carry. In a booking message, meaning a service’s Confirmation message, Reminder message and Cancellation message, and the Book Meeting step’s own confirmation, either family resolves.
After a Book Meeting step, only {{meeting.*}} resolves. The step writes the meeting tokens for the steps that follow it and nothing else, which is what its own panel hint says: “Books on your Google Calendar with a Meet link, then exposes {{meeting.link}}, {{meeting.date}} and {{meeting.time}} for later steps.” An {{appointment.date}} in a step after Book Meeting comes out empty. Worse, in a flow an appointment event started, it resolves to the appointment that started the flow, not the one just booked.
For class events:

Finance

Filled in flows started by the matching Business event, and by the finance steps that create the thing mid-flow. Amounts are plain numbers: 120.00, no currency symbol. Put the currency token next to them yourself: {{invoice.total}} {{invoice.currency}}.

Offerings

E-commerce (Shopify / WooCommerce)

Filled in flows started by a store event, and by the FOUND branch of a Find Order step in any flow.

WhatsApp cart

Filled in flows started by the Cart order received trigger. See Sell on WhatsApp. These aren’t in the picker; type them.

Shared location

Filled after a contact shares a location: on the RECEIVED path of a Request Location step, or in a flow a shared-location message started. Empty if the contact replied without actually sharing a pin.

WhatsApp Flow (form) submissions

Filled when a contact submits a WhatsApp form that a WhatsApp Form (Flow) step sent earlier in the same flow. Empty if the contact replied without submitting the form, because that step moves on either way. These aren’t in the picker; type them. <field> is the field’s internal name, not the wording of the question you wrote. It’s the small label on the row in the contact’s Flow answers panel, so send yourself the form once, submit it, and read the names (and the stored values) off that panel. Two limits. An answer that arrives as a list of choices resolves to nothing, though the list itself still shows in Flow answers. And a Condition step can’t test an answer: conditions compare literal text (see the three rules). To branch on something, ask for it with a normal question step, where the reply is captured and can be branched on.

More tokens you can type

The picker stops at the everyday set; the engine resolves more. The useful ones, same scoping rules:

Where variables work

Inside a flow, nearly every text a contact ends up seeing takes variables: message bodies and captions, question steps, button and card text, WhatsApp template parameters, the AI step’s instructions, the HTTP Request step’s JSON body, the Send SMS step’s message, payment-request amounts and descriptions. Outside the flow builder (broadcast messages, sequence steps, quick-automation replies, Bot Setup welcome messages and menu answers), the same {{syntax}} works but only the contact-level set resolves, as covered in rule 3.

Build a flow

The canvas these tokens live on.

Custom fields

Create the fields behind the custom tokens.

Store automations

The steps that fill the e-commerce tokens.

HTTP Request step

Mint your own variables from an API response.