Message flows run on WhatsApp in this release. Other channels are on the roadmap; a flow bound to any other channel is refused at publish.
Ask steps send a question and wait for the answer. Each one stores what came back in a variable and leaves by a branch that says what happened — the tap, the typed answer, a timeout, or an answer that did not fit.
This is the reference for the Ask group of the flow builder's palette. Every step below is listed with what it does, the settings it takes, the branches it can leave by and the one thing to keep in mind. Settings marked "templated" accept {{vars.x}}, {{contact.name}} and {{last.text}}.
Buttons
Up to three reply buttons. One out per button.
| Setting | What it does |
|---|---|
body |
The question above the buttons. |
header |
Optional header line. |
footer |
Optional footer line. |
buttons |
Up to 3 of {id, title}; each id becomes an out of this node. |
store_as |
Optional variable to store the tapped button id in. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: timeout window_closed — One out per config.buttons[].id, plus timeout.
Keep in mind: At most three buttons of 20 characters. A tap on an older menu re-asks the current question instead of jumping.
List
Up to ten rows across sections. One out per row.
| Setting | What it does |
|---|---|
body |
The text above the list. |
header |
Optional header line. |
footer |
Optional footer line. |
button |
Label on the button that opens the list (default "Choose"). |
sections |
[{title, rows: [{id, title, description}]}], at most 10 rows in all; each row id becomes an out. |
store_as |
Optional variable to store the chosen row id in. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: timeout window_closed — One out per row id across config.sections[].rows[], plus timeout.
Keep in mind: At most ten rows in all. The customer may also type the row number or its title.
Ask text
Wait for a typed answer and store it, with optional validation.
| Setting | What it does |
|---|---|
body |
The question to ask. |
store_as |
Variable to store the typed answer in (required). |
validate |
Optional: none, or any value kind — text, number, integer, decimal, money, percent, boolean, date, datetime, time, email, phone, url, uuid, id, regex, in, length, range, required. A miss leaves by invalid after the retries, and a hit stores the cleaned-up answer (number → a number, email → lower-cased, phone → 255712345678, date → YYYY-MM-DD). |
pattern |
The regular expression when validate is regex (or id). |
min |
With validate: the smallest number, the earliest date, or the fewest characters allowed. |
max |
With validate: the biggest number, the latest date, or the most characters allowed. |
decimals |
With validate number, decimal, money or percent: how many decimal places to keep. |
currency |
With validate money: the three-letter code, default TZS. |
country |
With validate phone: the two-letter country a leading 0 belongs to, default TZ. |
values |
With validate in: the list of answers that count, matched case-insensitively. |
accept_caption |
Optional true: the caption on a photo or document counts as the typed answer. Off, a sticker, pin, contact card, cart, form or file is re-asked, never stored ({{last.kind}} says what arrived). |
join_burst |
Default true: two or three bubbles typed within 10 seconds of each other ("John" / "Doe") are stored as one answer joined with newlines. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: ok invalid timeout window_closed
Keep in mind: A sticker, photo, pin, contact card or cart is re-asked, never stored — accept_caption lets a photo caption count.
Confirm
A yes / no question, rendered as two buttons.
| Setting | What it does |
|---|---|
body |
The yes / no question. |
header |
Optional header line. |
footer |
Optional footer line. |
yes_label |
Label on the yes button (default "Yes"); the out stays "yes". |
no_label |
Label on the no button (default "No"); the out stays "no". |
store_as |
Optional variable to store yes or no in. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: yes no timeout window_closed
Keep in mind: Typed ndiyo / hapana, yes / no and 1 / 2 count as well as the buttons.
WhatsApp form
A native WhatsApp Flow form. Answers land in variables.
| Setting | What it does |
|---|---|
flow_id |
The WhatsApp Flow id from Meta's Flow Builder. |
body |
Message text sent with the form button. |
cta |
Label on the button that opens the form. |
screen |
Optional first screen id of the form. |
prefill |
Optional [{name, value}] to pre-populate form fields (templated). |
map |
Optional {form_field: variable} to copy individual answers into variables. |
store_as |
Optional variable to store all answers in as one object. |
mode |
Optional draft while the form is still a draft in Meta's Flow Builder; blank means published. |
retry_prompt |
What to say when the customer types instead of opening the form (default: "please use the Open form button above"). The original timeout stands; after the retries the node leaves by invalid, then abandoned, then timeout. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
Branches: submitted invalid abandoned timeout window_closed
Keep in mind: The form itself is built in Meta's Flow Builder; only the fields you map land in variables.
Ask for a file
Wait for a photo or document — proof of payment, an ID.
| Setting | What it does |
|---|---|
body |
What to ask for. |
accept |
Optional list of image, video, audio, document, sticker and/or mimes such as application/pdf or image/*; blank accepts anything, a mismatch leaves by wrong_type. |
store_as |
Variable to store the received file in: {url (signed link, no login, valid 30 days), path, disk, mime, type, size_bytes, filename, sha256, message_id, whatsapp_media_id, status, expires_at}. The local copy is what the flow owns — Meta's media id expires. A download the router could not complete leaves by failed with vars.__media_error. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: ok wrong_type failed timeout window_closed
Keep in mind: Meta's media link expires, so the flow keeps its own copy; the signed link in the variable lasts 30 days.
Ask for the cart
Wait for the customer to send their WhatsApp cart, and read what is in it.
| Setting | What it does |
|---|---|
body |
What to say while waiting — usually "tap Send cart when you are done". |
store_as |
Variable to store the cart in: {catalogue_id, items[{retailer_id, quantity, unit_price_minor, line_total_minor, currency}], count, quantity, subtotal_minor, subtotal, currency, note}. Defaults to cart. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: received no_items timeout window_closed
Keep in mind: Needs a connected catalogue; the cart arrives when the customer taps Send cart.
Ask for location
Request a pin with WhatsApp's own location prompt.
| Setting | What it does |
|---|---|
body |
Text sent with WhatsApp's location request. |
store_as |
Variable to store the pin ({latitude, longitude, name, address}) in. |
accept_text |
Optional true: a typed address counts and is stored as {address}. Off, typing re-asks with the location request, then leaves by invalid. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: ok invalid timeout window_closed
Keep in mind: Uses WhatsApp's own location request; a typed address only counts with accept_text.
Link button
A button that opens a URL. It does not wait for a reply.
| Setting | What it does |
|---|---|
body |
The message text above the button. |
display_text |
Label on the button. |
url |
The URL the button opens (templated). |
Branches: next window_closed
Keep in mind: It does not wait — the next step runs at once.
Numbered menu
A plain-text "1. … 2. …" menu — how a list reads on SMS.
| Setting | What it does |
|---|---|
body |
The text above the numbered items. |
items |
[{id, label}] rendered as "1. label"; each id becomes an out, and the customer replies with the number. |
store_as |
Optional variable to store the chosen item id in. |
retries |
How many times to re-ask after an answer that does not fit, before leaving by timeout (0–5, default 1). |
timeout_minutes |
Give up waiting for a reply after this many minutes and leave by timeout. |
retry_prompt |
What to say when the answer does not fit and there is a retry left. |
Branches: timeout window_closed — One out per config.items[].id, plus timeout.
Keep in mind: A plain-text menu; the customer answers with the number (or the title).
Where next
- Open the builder at Message flows and drag any of these onto the canvas — the panel on the right shows the same settings.
- New to flows? Start with Build your first WhatsApp flow.
- The other groups: Say · Think · Decide · Wait · Do · Route.
- The rules every flow lives under: the 24-hour window, payments, what we keep and why a flow stops.