{{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”. To avoid the hole, give the token a fallback after a
pipe: {{first_name|there}} renders “there” when the contact has no first name. Blank or
whitespace counts as empty; 0 is kept. It works on any token, including {{custom.x}}, in
flows, quick automations, broadcasts and sequences. It matters most for WhatsApp templates,
because WhatsApp rejects a blank template parameter. 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. Flows and quick automations get the full set. A quick automation resolves the same
event tokens as a flow started by the same event, so {{cart.total}} or {{invoice.total}}
works in its reply. Only tokens written by flow steps (Find Order, Book Meeting, HTTP Request
and so on) and {{flow_run_id}} are flow-only.
Broadcasts, sequences and Bot Setup
replies substitute contact-level tokens only: the Contact, Business and System tables below
(all but {{flow_run_id}}), plus the two live balances.
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.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.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.
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. The FOUND branch of a Find Order step fills only the order tokens (order.id, order.number, order.total, order.currency, order.status,
order.payment_status, order.fulfillment_status, order.checkout_url, order.tracking_url,
order.tracking_number, order.items_summary) and {{store.name}}. Customer, product and
payment-method tokens come only from a store-event trigger.
WhatsApp cart
Filled in flows started by the Cart order received trigger. See Sell on WhatsApp. These aren’t in the picker; type them.Click-to-WhatsApp ad
Filled when the message that started the flow came from a tap on one of your ads, or on a post that opens a WhatsApp chat. See the Click-to-WhatsApp ad trigger. These aren’t in the picker; type them.
Each token only carries what Meta actually sent: an ad with no body copy leaves
{{ad.body}} empty,
and a very long one arrives cut off at 1,000 characters. {{ad}} on its own resolves to nothing, so
always name the part you want. DMLY doesn’t report {{ad.ctwa_clid}} to Meta for you yet; it is there so you
can pass the click on to Meta’s own tools if you track sales back to ads.
They aren’t limited to flows built on the ad trigger. Any flow that this message started gets them,
so a plain WhatsApp message flow can still name the ad. A flow that was already running before
the tap doesn’t get them: they’re set when a run starts.
Answering the offer somebody tapped. A salon running an ad headlined Summer Sale: two for one
can open with that offer instead of a greeting:
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. Quick-automation
replies get the event tokens too; the others resolve only the contact-level set, 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.

