Flows are interactive conversational menus that run inside WhatsApp and guide a contact through a multi-step dialogue — presenting buttons, collecting free-text replies, branching on variables, and optionally handing off to a human agent. Unlike Automations, which are silent background workflows that execute a fixed step list, Flows maintain live state for each contact and wait for their responses before advancing. When a Flow is handling a conversation, it takes priority over the AI auto-reply bot and over automations — nothing else runs on that message until the Flow finishes or hands off.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ArnasDon/wacrm/llms.txt
Use this file to discover all available pages before exploring further.
Node types
A Flow is a directed graph of nodes connected by edges. Each node has anode_type that determines what it does and what configuration it requires. The runner advances through nodes automatically after send nodes land, or waits for the contact’s next reply on interactive and input nodes.
start
The entry point of every Flow. Holds a single
next_node_key pointing at the first real node. Every Flow has exactly one start node; the runner enters here on trigger.send_message
Sends a plain text message to the contact. Supports
{{vars.X}} variable interpolation in the message body. Auto-advances to next_node_key after the message lands at Meta — no contact reply required.send_buttons
Sends a message with up to 3 tappable reply buttons. Each button has a
reply_id (used for routing), a visible title (≤ 20 characters per Meta’s limit), and its own next_node_key. The runner routes to the button’s target node when the contact taps it.send_list
Sends a tap-to-expand list message with sections and rows. Each row has a
reply_id, title, optional description, and next_node_key. Supports optional header_text, footer_text, and a configurable button_label for the expand affordance.send_media
Sends an image, video, or document. The file is uploaded to the
flow-media Supabase Storage bucket via the builder’s file picker; media_url is the public URL Meta fetches at send time. Supports an optional caption (with {{vars.X}} interpolation) and, for documents, an optional filename. Auto-advances after send.collect_input
Sends a prompt message to the contact and waits for their free-text reply. The reply is stored into
flow_runs.vars under the configured var_key, then the run advances to next_node_key. Downstream nodes can reference the captured value via {{vars.var_key}}.condition
Branches without sending a message. Evaluates a predicate over a stored variable (
var), the contact’s tags (tag), or a contact profile field (contact_field). Routes to true_next when the predicate passes, or false_next when it doesn’t. Supported operators: equals, contains, present, absent.set_tag
Adds or removes a tag on the contact (controlled by
mode: "add" | "remove"). The tag is selected from your existing tags in the builder. Auto-advances to next_node_key after the tag operation completes.handoff
Terminates the Flow run with a
handed_off status and optionally assigns the conversation to a specific agent. An internal note can be written to the run events log for context. After handoff the contact is free to start a new Flow or receive messages from an agent.end
Terminal node — stops the run cleanly with a
completed status. Carries no configuration. Every path through a Flow must terminate at either an end or a handoff node.Variable interpolation
Anysend_message, send_media caption, or collect_input prompt can embed the value of a captured variable using the {{vars.X}} syntax, where X is the var_key set by an upstream collect_input node.
flow_runs.vars and are scoped to the current run only — they do not persist between separate Flow runs for the same contact.
Triggers
Flows start when an inbound message matches the Flow’s configured trigger. The runner checks all active Flows in your account against every inbound message.| Trigger type | When it fires |
|---|---|
keyword | The inbound message contains (or exactly matches) one of the configured keywords. Case-sensitive matching is optional. |
first_inbound_message | The contact is sending their very first message to your number. |
manual | The Flow is started manually from the conversation view — it does not fire automatically on inbound messages. |
Fallback policy
When a contact sends a reply that does not match any button or list row in asend_buttons or send_list node, the runner applies the Flow’s fallback policy:
| Setting | Options |
|---|---|
on_unknown_reply | reprompt — re-send the prompt; handoff — hand off to a human; ignore — discard and wait |
max_reprompts | Number of reprompt attempts before on_exhaust applies (default: 2) |
on_timeout_hours | Hours before a stale run is swept as timed_out (default: 24) |
on_exhaust | handoff or end — what to do once max_reprompts is reached |
Building a Flow
Create a new Flow
Go to Flows in the sidebar and click New flow. The dialog gives you the option to start blank or clone one of the pre-built templates (Welcome menu, FAQ bot, Lead capture).
Add nodes on the canvas
The builder uses a node canvas powered by @xyflow/react. Click Add node to insert a node of any type. Each node opens an inline config form where you set the message text, button labels, variable keys, and routing targets.
Connect nodes with edges
Every routing target (
next_node_key, per-button next_node_key, true_next, false_next) is expressed as the stable string node_key of the destination node — not a UUID — so Flows can be cloned or templated without rewriting references. The builder’s visual canvas wires these as edges between node cards.Validate
The live validator runs at save time and catches missing edges, orphaned nodes, or nodes with no route to
end/handoff. Validation issues are clickable: clicking a warning jumps to and highlights the offending node.Meta enforces hard limits on interactive message types: button messages are capped at 3 buttons, and list messages are capped at 10 rows total across all sections. The Wacrm validator and the Meta API layer both enforce these limits — exceeding them at save time produces a validation error; exceeding them at send time returns a Meta API error in the run events log.
Flow run history
Every execution of a Flow is recorded as aflow_run row, and every step the runner takes is written as a flow_run_event. To inspect the execution history for a specific Flow:
- Open Flows in the sidebar.
- Click the Flow you want to inspect.
- Select the Runs tab — or navigate directly to
/flows/[id]/runs.
completed, handed_off, timed_out, paused_by_agent, or failed), and a step-by-step event log including which node was active at each point.
Relationship to Automations and the AI bot
Flows always take priority over both Automations and the AI auto-reply bot. The inbound webhook checks active Flows first:- If a Flow consumes the message (either by advancing an existing active run or starting a new one), Automations do not fire on that message and the AI bot does not run.
- Only if no Flow handles the message does the automation engine evaluate its triggers, followed by the AI bot for any remaining unassigned messages.