Building your first flow
This guide assumes you’ve completed the Quickstart and have a workspace with WhatsApp connected. We’ll build a competition entry flow that collects a name and South African ID, validates the ID, and branches on whether the contact is over 18.
What you’ll build
Section titled “What you’ll build”start → message "Welcome! Please enter the competition." → question "What's your full name?" → stored in full_name → question "Enter your ID number." → stored in sa_id → validation is_valid_sa_id(sa_id) ├─ valid → condition age_from_id(sa_id) >= 18 │ ├─ true → submission │ └─ false → message "You must be 18 or older." → end └─ invalid → message "That ID looks wrong. Try again." → loop back to sa_id question (max 2 retries)Step-by-step
Section titled “Step-by-step”-
Create the flow shell. Flows → New flow → name it
Competition entry. Open the builder. -
Add the opening message. Drag a Message node onto the canvas, connect it from
start, and set the body:Welcome! Please enter the competition. -
Add the name question. Drag a Question node, connect from the message. Configure:
- Prompt:
What's your full name? - Variable name:
full_name - Required: yes
- Prompt:
-
Add the ID question. Another Question node:
- Prompt:
Great. Now enter your ID number. - Variable name:
sa_id - Required: yes
- Prompt:
-
Add validation. Drag a Validation node. Pick the built-in
sa_id_checksumvalidator against thesa_idvariable. The node automatically produces two outgoing edges:validandinvalid. -
Handle the invalid path. From the
invalidedge, drag a Message node:That ID looks wrong. Try again.Wire its output back to the ID question. Use the Retry limit on the validation node (default 2) so the contact can’t loop forever.
-
Add an age branch. From the
validedge, drag a Condition node. Configure:- Variable:
sa_id - Operator:
custom:age_from_id - Compare to:
18 - Comparison:
>=
- Variable:
-
Submission path (18+). From the condition’s
trueedge, drag a Submission node. Title itCompetition entry. This writes{ full_name, sa_id }to theentriestable. -
Rejection path (under 18). From the condition’s
falseedge, drag a Message node:Sorry, you must be 18 or older to enter.Then an End node.
-
Preview. Click Preview in the top-right. Voxa spawns a sandbox conversation scoped to your own account — step through the flow as if you were a contact. Catch wording, variable-name, and branching bugs here before a real contact ever sees them.
-
Publish. Click Publish. Voxa snapshots this flow as version 1 (or the next number) and marks it as the active published version. A fresh draft version is created automatically for any future edits — live conversations keep running on the version they started on.
Good patterns
Section titled “Good patterns”- Name your variables consistently.
full_name,email,sa_id,address_line_1— future-you reading an entry export will thank you. - Always validate free-text input. Especially emails and IDs; invalid data at collection time becomes a data-cleanup job later.
- Use
Delaysparingly. A 1–2 second pause before a follow-up question reads as natural; 10+ seconds feels broken and WhatsApp will think the contact has abandoned. - Keep flows small. Prefer five focused flows over one 40-node monster. Small flows are easier to version, debug, and retire.
Anti-patterns
Section titled “Anti-patterns”- Collecting sensitive personal information without a clear reason. You are the Responsible Party under POPIA / Controller under GDPR — see Voxa’s Privacy Policy.
- Hard-coding tenant-specific literals inside flow copy. Store them in
contact
custom_fieldsor flow variables so one flow can serve many campaigns. - Publishing a flow without clicking Preview first.
What’s next
Section titled “What’s next”- Handling conversation state — timeouts, resumes, and the 24-hour window.
- Working with prompts — wording patterns that work on WhatsApp.
- Production checklist — before you flip live.