> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soneka.africa/llms.txt
> Use this file to discover all available pages before exploring further.

# Flow Builder: Automate Multi-Step WhatsApp Journeys

> Visual drag-and-drop builder for WhatsApp automations. Send messages, ask questions, branch on answers, call APIs, book appointments, sell products — with AI-generated starters and full engine support.

<Frame>
  <img src="https://mintcdn.com/soneka-africa/XXyrTGYVNgSvQUD1/images/image-12.png?fit=max&auto=format&n=XXyrTGYVNgSvQUD1&q=85&s=8d68c52f44b76cee8a9d761a688c2417" alt="Image" width="1865" height="831" data-path="images/image-12.png" />
</Frame>

The **Flow Builder** is Soneka's visual automation engine for designing multi-step WhatsApp conversations that run without a human in the loop. A flow is a **drag-and-drop graph** of steps (nodes) joined by connectors that map the path from one step to the next. Exactly one step is the **trigger** — the entry point that decides which contacts enter the flow and when.

You design the flow on the canvas; when you save, it's stored, and when it runs, Soneka walks through the steps one by one and sends the right WhatsApp message for however your number is connected. Whether you're recovering abandoned carts, running OTP flows, booking appointments, or qualifying leads, flows let you build logic that would otherwise take an engineering team.

<Info>
  **Works with any engine.** The builder runs on all three WhatsApp connections. The same step sends correctly whether your number is on the Unofficial API, the official Cloud API, or Twilio. Where a connection can't show something the normal way (Twilio has no tappable buttons or lists, for example), Soneka falls back to a numbered text menu and reads the number the customer types back. See [Engine notes](#engine-notes).
</Info>

***

## Two Kinds of Flow

When you click **New flow**, Soneka asks which kind you want to build:

<Frame>
  <img src="https://mintcdn.com/soneka-africa/XXyrTGYVNgSvQUD1/images/flow-type-picker.png?fit=max&auto=format&n=XXyrTGYVNgSvQUD1&q=85&s=141bae52ea474c8dc85cc3907a0e6567" alt="What kind of flow? — Messaging or Call" width="499" height="324" data-path="images/flow-type-picker.png" />
</Frame>

| Flow type          | Runs on                                                               | What it does                                                                                                                                  |
| ------------------ | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Messaging flow** | WhatsApp or Instagram (switch the channel on the Trigger node)        | Multi-step chat automation — sends messages, asks questions, branches on answers, calls APIs, books appointments, sells products.             |
| **Call flow**      | AI voice calls (see [AI Call Assistant](/features/ai-call-assistant)) | A spoken AI voice IVR — say lines, listen for the caller, branch by intent or key press, run web lookups, and transfer to a human or hang up. |

The canvas, connectors, variables, and trigger concept are the same for both — only the **step palette** changes. Everything below applies to messaging flows unless the section is explicitly labeled **Call flow**. Jump to [Call flow step reference](#call-flow-step-reference) for the voice palette.

<Tip>
  Pick the type once at creation time. If you need both a chat journey and a phone journey for the same use case (for example, an appointment booking that works over text *and* over the phone), build one of each and share a common tag or contact attribute between them.
</Tip>

***

## Flows vs. Broadcasts

|                     | Flows                    | Broadcasts                     |
| ------------------- | ------------------------ | ------------------------------ |
| **Initiated by**    | Trigger event or keyword | You (scheduled or event-fired) |
| **Message count**   | Many (multi-step)        | One (single template)          |
| **Branching logic** | Yes — infinite branches  | No                             |
| **Human handoff**   | Yes — escalate mid-flow  | No                             |
| **Best for**        | Automation journeys      | Campaigns and announcements    |

<Note>
  Flows and broadcasts work together. A common pattern: send a broadcast to re-engage a lapsed customer, then enroll anyone who replies into a flow that qualifies their interest and routes them to a sales agent.
</Note>

***

## Core Concepts

<Frame>
  <img src="https://mintcdn.com/soneka-africa/XXyrTGYVNgSvQUD1/images/image-13.png?fit=max&auto=format&n=XXyrTGYVNgSvQUD1&q=85&s=57dc5a2179166742256eb10fbfb24b5c" alt="Image" width="1902" height="897" data-path="images/image-13.png" />
</Frame>

* **Draft → Live → Paused.** A new flow starts as a **draft**. Publishing makes it **live**. Turning a live flow off makes it **paused** — it stops enrolling new contacts but keeps its design intact. The flows list shows each flow's status.
* **Trigger step.** Exactly one per flow, always the first step. Every save records the trigger so Soneka can quickly find which flows a tag or group should start.
* **Variables & merge tags.** Question steps save the customer's answer into a named variable. Reuse it later in any message with a `{{var}}` tag (e.g. `Thanks {{name}}!`). Soneka fills in the saved value when the message is sent.
* **Branches.** Some steps split the path. A **Condition** has `yes` / `no`; **Book Appointment** has `booked` / `no slots`; commerce steps have `purchased` / `abandoned`; multi-option steps (Buttons, List, Poll) give one branch per option.
* **Subscribers.** Every contact running through a flow is a **subscriber**, shown as `active`, `paused`, `completed`, or `failed`. You can view and pause/resume them per flow.
* **Scoped to workspace and connection.** Flows belong to a workspace, and the list shows the flows for your workspace's current WhatsApp connection. Any teammate with the admin role can build and manage them.

***

## Triggers

The trigger's **type** decides how contacts enter the flow. There are four types:

| Trigger type      | Fires when                                                                                    |
| ----------------- | --------------------------------------------------------------------------------------------- |
| **Keyword**       | A customer sends a WhatsApp message matching one of your keywords (e.g. `hi, hello, start`).  |
| **Tag added**     | A specific tag is added to a contact (manually, by a rule, or by a Tag step in another flow). |
| **Group join**    | A contact is added to a specific contact group.                                               |
| **Manual enroll** | You add contacts by hand from the flow's **Enroll** action.                                   |

### Setting the trigger

<Steps>
  <Step title="Open the trigger step">
    Open the flow and click the **trigger** step (always first on the canvas).
  </Step>

  <Step title="Pick the type">
    In the side panel, choose Keyword, Tag added, Group join, or Manual enroll.
  </Step>

  <Step title="Fill in the specifics">
    * **Keyword** — type a comma-separated list (e.g. `hi, hello, start`).
    * **Tag added / Group join** — pick the real tag or group from the dropdown.
    * **Manual enroll** — no config; you'll add contacts from the Enroll action later.
  </Step>

  <Step title="Optionally bind a device">
    Choose which connected number launches the flow (see [Device binding](#device-binding)).
  </Step>

  <Step title="Save">
    Save the flow. If you later rename a tag or change the trigger type, just save again to keep everything in sync.
  </Step>
</Steps>

<Info>
  **How matching works.** When a tag is added or a contact joins a group, Soneka finds the **published and active** flows whose trigger matches and enrolls the contact into each one. Keyword triggers are matched against incoming messages. A draft or paused flow never enrolls anyone.
</Info>

***

## Step Reference

The palette groups steps by purpose, matching what you see on the builder's left panel. "Branches" shows where you can wire the path onward from that step.

### Start

| Step        | What it does                                                                                                     | Branches        |
| ----------- | ---------------------------------------------------------------------------------------------------------------- | --------------- |
| **Trigger** | The entry point of every flow. Exactly one per flow, always first. See [Triggers](#triggers) for the four types. | One path onward |
| **End**     | Stop this branch of the flow.                                                                                    | —               |

### Send

| Step              | What it does                                                                                                       | Branches        |
| ----------------- | ------------------------------------------------------------------------------------------------------------------ | --------------- |
| **Send message**  | Send a single plain-text message (can include `{{var}}` personalisation).                                          | One path onward |
| **Send template** | Send an approved WhatsApp template by name. Soneka loads its content when you save, so it sends fast.              | One path onward |
| **Send media**    | Send one image, video, audio, or document, with an optional caption.                                               | One path onward |
| **Send sequence** | Stack several replies — text and media — into one node, with a short pause between each.                           | One path onward |
| **Quick replies** | Tap-to-pick reply buttons (max 3). Each option gives you a branch.                                                 | One per option  |
| **List message**  | Interactive list picker (up to 10 rows). Each option gives you a branch. You can set the "open list" button label. | One per option  |

### Listen

| Step             | What it does                                                                                                                                                                                          | Branches                                    |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| **Ask question** | Ask a question and save the typed answer to a variable. You can require the answer to be a valid email, phone, or number. If you list expected answers, the reply is routed down the matching branch. | One per expected answer, or one path onward |

### Logic

| Step              | What it does                                                                                                                                                                                                                           | Branches        |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| **Condition**     | If / else branch based on one or more variable rules combined with AND/OR.                                                                                                                                                             | `yes` / `no`    |
| **Wait**          | Pause for X seconds, minutes, hours, or days before continuing.                                                                                                                                                                        | One path onward |
| **Webhook**       | Call an external HTTPS endpoint. Insert your variables into the request and optionally save the response to a variable.                                                                                                                | One path onward |
| **Run code (JS)** | Sandboxed JavaScript transform. Run a short script over your flow variables (string manipulation, math, formatting) and save the result back to a variable. Runs in an isolated sandbox with a short time limit and no network access. | One path onward |
| **MySQL Query**   | Run a **read-only** SQL query against a connected MySQL database and map columns into flow variables. Configure the connection under **Settings → Integrations → MySQL**. Writes are blocked for safety.                               | One path onward |
| **Run sub-flow**  | Call another flow, then come back and continue this one.                                                                                                                                                                               | One path onward |

**Condition checks:** `equals`, `does not equal`, `contains`, `does not contain`, `greater than`, `less than`, and `is empty`. Text comparisons ignore capitalisation and surrounding spaces; `greater than` / `less than` treat both sides as numbers. With several rules you choose AND/OR between them; the flow takes the first match.

<Warning>
  **Run code (JS) and MySQL Query are power-user steps.** Bad scripts or slow queries can stall a subscriber. Test against a single throwaway contact before enabling a flow that uses them for a broader audience.
</Warning>

### AI

| Step             | What it does                                                                                                                                                                                           | Branches        |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------- |
| **AI assistant** | Reply with ChatGPT or Gemini. Ask an AI model a question (with the conversation as context), then save and send the reply. You can only pick the providers your admin enabled under **Settings → AI**. | One path onward |

### Contact

| Step             | What it does                                                                                             | Branches        |
| ---------------- | -------------------------------------------------------------------------------------------------------- | --------------- |
| **Tag contact**  | Add or remove a tag on the contact. Use an existing tag or type a new name to create one.                | One path onward |
| **Assign agent** | Hand off to a human. Route the conversation to a team queue (or a specific agent) with an internal note. | One path onward |

### Engage

| Step                 | What it does                                                                                                                                                         | Branches              |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| **Call to action**   | CTA button — up to 3, combining Visit (link), Call (phone), and Copy (code). On the Cloud API only one link shows as a tappable button; the rest appear in the text. | One path onward       |
| **Location**         | Send a map pin (name, address, coordinates).                                                                                                                         | One path onward       |
| **Poll**             | Send a poll with 2–12 options; optionally allow multiple choices.                                                                                                    | One per option        |
| **Chatbot**          | Trigger another chatbot — hand the conversation to one of your AI agents for a self-contained chat.                                                                  | One path onward       |
| **Book appointment** | Pick a Google Calendar slot. Offer open slots as a list, book the chosen one on your calendar, and confirm.                                                          | `booked` / `no slots` |
| **Google Meet**      | Create and send a Google Meet link during the flow, with a lead time before the meeting starts.                                                                      | One path onward       |
| **WhatsApp form**    | Send a published Meta form as an interactive message. **Official Cloud API only.**                                                                                   | One path onward       |

### Commerce

| Step              | What it does                                                           | Branches                  |
| ----------------- | ---------------------------------------------------------------------- | ------------------------- |
| **WhatsApp Shop** | Open your WhatsApp catalog inside the chat and watch for a purchase.   | `purchased` / `abandoned` |
| **WooCommerce**   | Send a WooCommerce product (or product list) and watch for a purchase. | `purchased` / `abandoned` |
| **Shopify**       | Send a Shopify product (or product list) and watch for a purchase.     | `purchased` / `abandoned` |

For all three commerce steps, `purchased` runs when the customer buys; `abandoned` runs after the wait time if they don't.

### Integrations

| Step              | What it does                                                                                                                            | Branches            |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| **Google Sheets** | Write or read a row. Append a new row, or look up a row by a matching value and save its cells into variables.                          | One path onward     |
| **Google Docs**   | Generate from a template. Copy a template document, fill in the placeholders, share it with anyone who has the link, and send the link. | One path onward     |
| **Google Form**   | Send a link and capture answers. Send the form and pause; the flow continues once it's submitted.                                       | Continues on submit |

### CRM

| Step                   | What it does                                                                                                                                                                  | Branches        |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| **Create / move deal** | Create a new deal in your [Sales Pipeline](/features/deals), or advance an existing one to a new stage. Set title, value, owner, tags, and custom fields from flow variables. | One path onward |

If a step ever can't be understood (for example, after a future change), it's skipped with a warning rather than breaking the whole flow.

<Info>
  **Connection notes (quick view):** the **WhatsApp form** step only works on the Cloud API. The Google steps need the workspace's Google account connected (same connection used for Calendar). The **MySQL Query** step needs a MySQL connection configured under **Settings → Integrations**. On Twilio, tappable steps (Quick replies, List message, Call to action) become numbered text. Full detail in [Engine notes](#engine-notes).
</Info>

***

## Call Flow Step Reference

When you pick **Call** at the "What kind of flow?" prompt, the canvas loads a voice-specific palette in place of the messaging one. Everything else about the builder — trigger, variables, branches, subscribers, save/publish — works exactly the same way. Call flows run on Soneka's voice engine and drive [AI Call Assistant](/features/ai-call-assistant) sessions.

<Frame>
  <img src="https://mintcdn.com/soneka-africa/XXyrTGYVNgSvQUD1/images/call-flow-palette-1.png?fit=max&auto=format&n=XXyrTGYVNgSvQUD1&q=85&s=090a864cd791bae93159dffc7060425c" alt="Call flow palette — Start, Logic, Voice" width="242" height="583" data-path="images/call-flow-palette-1.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/soneka-africa/XXyrTGYVNgSvQUD1/images/call-flow-palette-2.png?fit=max&auto=format&n=XXyrTGYVNgSvQUD1&q=85&s=752ac0eb17fada6959395387c903b781" alt="Call flow palette — Call Routing, Call Control" width="247" height="284" data-path="images/call-flow-palette-2.png" />
</Frame>

### Start

| Step        | What it does                                                                                                                        | Branches        |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| **Trigger** | Where the flow starts. For a call flow, it fires when a caller reaches your AI-answered number. Exactly one per flow, always first. | One path onward |
| **End**     | Stop the flow here. Ends this branch cleanly (the call itself is closed by **Hang up**).                                            | —               |

### Logic

| Step              | What it does                                                                                                                                                                                                 | Branches        |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------- |
| **Condition**     | If / else branch on a variable — the same rule engine as messaging flows (`equals`, `contains`, `greater than`, etc.).                                                                                       | `yes` / `no`    |
| **Wait**          | Pause for X minutes before continuing. Useful before a callback or a scheduled follow-up action.                                                                                                             | One path onward |
| **Webhook**       | Call an external HTTPS endpoint. Insert variables into the request and save the response back to a variable — same behaviour as in messaging flows.                                                          | One path onward |
| **Run code (JS)** | Sandboxed JavaScript transform. Manipulate variables (parse a phone number, format a date, do a calculation) and save the result. Runs in an isolated sandbox with a short time limit and no network access. | One path onward |

<Warning>
  **Keep Logic steps fast.** A caller is on the line while the flow runs. Long **Wait** durations, slow **Webhook** endpoints, or heavy **Run code** scripts create dead air. Aim for sub-second responses; if a step must take longer, add a **Say** first ("One moment while I look that up…") so the caller isn't sitting in silence.
</Warning>

### Voice

The voice steps are the heart of a call flow — they're what actually happens on the phone.

| Step           | What it does                                                                                                                                                                 | Branches        |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| **Say**        | One path onward                                                                                                                                                              |                 |
| **Listen**     | Capture caller speech and save it to a variable. Transcribes what the caller says and stores it for use in later steps or conditions.                                        | One path onward |
| **AI Respond** | Let the AI answer, spoken back to the caller. The assistant uses the conversation so far (plus any training/knowledge base you attached) to generate a natural spoken reply. | One path onward |

<Tip>
  A common pattern is **Say → Listen → AI Respond**: greet the caller, capture what they need, and let the AI answer. Wrap that in a **Menu / Branch** or **Condition** when you want deterministic routing instead of open-ended chat.
</Tip>

### Call Routing

| Step              | What it does                                                                                                                                                                                              | Branches        |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| **Menu / Branch** | Route the call by **intent** (what the caller said) or by **digit** (DTMF key press). Give each option its own branch — for example *"press 1 for Sales, 2 for Support, or say what you need."*           | One per option  |
| **Search web**    | Look something up on the web and save the result to a variable. Handy for real-time facts (opening hours at another location, order status page, latest price) that shouldn't live in your training data. | One path onward |

### Call Control

| Step         | What it does                                                                                                                                                    | Branches |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| **Transfer** | Hand the call to a human. Point it at a phone number or a team; Soneka bridges the caller across and steps out of the loop.                                     | —        |
| **Hang up**  | End the call. Use as the final step on any branch that doesn't transfer — for example after a successful booking, or after a polite "thanks for calling" close. | —        |

<Info>
  **Call flow prerequisites.** Call flows require the [AI Call Assistant](/features/ai-call-assistant) feature to be enabled on your plan and at least one voice-capable number configured. Transcripts, recordings, and the timeline of steps that ran on each call are available in [Call Logs](/features/call-logs).
</Info>

***

## Build & Connect a Flow

<Steps>
  <Step title="Create the flow">
    Go to **Flows → Create Flow** (or open an existing one to edit). Give it a **name** and optional **category**.
  </Step>

  <Step title="Set up the trigger">
    Click the trigger step first — pick the type and, where relevant, the tag, group, or keywords. See [Setting the trigger](#setting-the-trigger).
  </Step>

  <Step title="Drag steps onto the canvas">
    The palette lives on the left. The canvas reads left to right.
  </Step>

  <Step title="Connect the steps">
    Drag from a step's output to the next step. Branching steps have several outputs — wire each to a different next step. For a Condition wire `yes` and `no`; for Buttons/List wire one per option; for commerce wire `purchased` and `abandoned`.
  </Step>

  <Step title="Configure each step">
    Open each step and fill in its settings. Use `{{var}}` tags in any message to reuse answers captured by earlier **Ask** steps.
  </Step>

  <Step title="End every branch">
    Finish each branch with an **End** step or a final message. An unconnected branch simply ends the flow there.
  </Step>

  <Step title="Save and publish">
    Click **Save** to store the flow, then **Publish** to make it live. Use **Pause** later to stop enrolling new contacts without deleting.
  </Step>
</Steps>

<Info>
  **Variables tip.** An **Ask** step saves into the variable you name (default `answer`); Buttons/List save into `choice` by default; the AI assistant saves into `reply`; a Webhook saves the response into `response`. Pick clear names and reuse them as `{{name}}`, `{{choice}}`, etc.
</Info>

***

## Build with AI

The builder can generate a starter flow from a plain-language description. Describe the automation (for example, *"Greet the customer, ask their name, then offer a list of services and book an appointment"*) and Soneka drafts a full flow — steps and connections — onto the canvas for you to refine.

<Frame>
  <img src="https://mintcdn.com/soneka-africa/XXyrTGYVNgSvQUD1/images/image-14.png?fit=max&auto=format&n=XXyrTGYVNgSvQUD1&q=85&s=a36ea8137e6566397484081393c74117" alt="Image" width="619" height="590" data-path="images/image-14.png" />
</Frame>

<Steps>
  <Step title="Open AI generate">
    In the builder, click **AI generate**.
  </Step>

  <Step title="Pick a provider and model">
    You can only pick the ones your admin enabled under **Settings → AI**.
  </Step>

  <Step title="Describe your flow">
    Type your description (up to **2000 characters**) and generate.
  </Step>

  <Step title="Review and refine">
    Edit the result on the canvas, then save and publish as usual.
  </Step>
</Steps>

**How it works:** the AI is instructed to build a clean flow — one trigger first, every branch finished, a left-to-right layout, `{{var}}` tags, and no emojis — and the result is capped at **up to 20 steps** before it appears on the canvas. You'll get a clear error if the provider isn't enabled or the AI returns something unusable.

<Warning>
  **Always review generated flows.** The AI produces a *starting point*. Check the trigger, wording, every branch, and any device/tag/group choices before publishing — and test against your own number first.
</Warning>

***

## Device Binding

A flow sends from one of the workspace's connected numbers. You can pick a specific number on the trigger step, or leave it unset to use the workspace default.

* The number picker matches your connection: on the Unofficial API it lists your paired, active phones; on the Cloud API or Twilio it lists your connected numbers.
* If you pick a number, the flow uses it — as long as it's still active and in this workspace.
* If you don't pick one (or the chosen one is gone), the flow uses the workspace's first active number.
* If no number is available when the flow tries to launch, the subscriber is marked **failed** with *"No connected device for this workspace"* — connect a number and enroll the contact again.

***

## Google, Commerce & Media Pickers

* **Google pickers.** The Google Sheets / Docs / Form steps let you pick a real spreadsheet, template document, or form from your connected Google account, and match its placeholders or columns to flow variables. These steps need the workspace's Google account connected — the same connection used for Calendar and appointments.
* **Commerce pickers.** The WhatsApp Shop / WooCommerce / Shopify steps let you pick a **store** and then choose products from it. Product details (name, image, price) are saved with the step so the cards display instantly. Older flows keep working — their products are upgraded automatically.
* **Media upload.** The Media and Sequence steps accept image, video, audio, and document files. Uploads are capped at **50 MB**.

***

## Enrolling & Subscribers

* **Keyword / tag / group flows** enroll contacts automatically when the matching event happens — but only while the flow is published and active.
* **Manual-enroll flows** are added by you: open the flow, choose contacts or a group, and enroll. The flow must be active. Enrolling the same contact twice does nothing if they're already running; a contact who previously **failed** gets retried.
* **Subscriber states:** `active`, `paused`, `completed`, `failed`. The flow's detail panel lists subscribers with their state, when they were enrolled, and any failure reason; the flows list shows active/completed/failed counts per flow.
* **Pause / resume a subscriber.** Pausing keeps that contact from being re-enrolled by tag/group triggers while you keep them muted — it doesn't stop a conversation already in progress. Resuming clears the pause and any failure, but deliberately doesn't restart the flow (that would double up on contacts mid-conversation).

<Warning>
  **Ban safety.** Flows send real WhatsApp messages. On the Unofficial API engine, aggressive automated sends to many cold numbers are a fast path to a number ban. Keep delays sensible, only enroll contacts who opted in, and avoid blasting identical messages to large audiences.
</Warning>

<Warning>
  **Don't test with live sends to real contacts.** A published flow will actually message people. Use a throwaway test contact you control — never enroll a real audience just to "see if it works".
</Warning>

***

## How a Flow Runs

When a contact is enrolled, Soneka starts a live conversation for that customer and works through the steps:

* **Step by step.** The flow begins at the first step and follows the connections. After each step it takes the branch the customer's reply chose and runs the next step. When a branch has nothing connected, that path ends.
* **Reading replies.** For Buttons, List, Poll, and Ask-with-options, the customer's reply chooses a branch. WhatsApp can send a reply in several different forms, and Soneka understands all of them, so a tap is routed correctly on any device or carrier. Typing a plain number (`1`, `2`…) also works as a fallback.
* **1-hour wait window.** A step that waits for the customer (List, Buttons, Ask, Poll, commerce) keeps the conversation open for up to **1 hour**. Idle conversations are cleaned up after that — long enough for a person to read and tap, short enough not to pile up.
* **Delays.** A Delay step simply waits the time you set before moving on.
* **Commerce waits.** A commerce step pauses for the wait time you set. If the customer buys, the flow takes `purchased`; if the time runs out first, it takes `abandoned`. The conversation isn't cancelled while waiting — a late reply can still produce a checkout link.
* **Appointments.** **Book Appointment** fetches open slots, sends them as a list, books the chosen one on your calendar, sends a confirmation, and takes `booked` (or `no slots` if nothing is free or the reply can't be matched).

***

## Engine Notes

Each step is sent through your workspace's current WhatsApp connection. Behaviour differs as follows:

| Capability                    | Unofficial API                | Official Cloud API                           | Twilio                                                     |
| ----------------------------- | ----------------------------- | -------------------------------------------- | ---------------------------------------------------------- |
| Text / media / location       | Full support                  | Full support                                 | Full support                                               |
| Buttons                       | Tappable buttons              | Tappable (max 3, labels trimmed to 20 chars) | **Falls back** to numbered text; customer types the number |
| List                          | Tappable list                 | Tappable (up to 10 sections of 10 rows)      | **Falls back** to numbered text                            |
| CTA link                      | Tappable                      | One tappable link button                     | Link shown in message text                                 |
| Template                      | Sent as plain text            | Sent as an approved template                 | Approved Twilio template if set up, otherwise plain text   |
| WhatsApp Form                 | Not available                 | Supported                                    | Not available                                              |
| Commerce (catalog / products) | Product cards + checkout link | Native product list / single product         | Product cards + checkout link                              |

* **Tappable steps fall back on Twilio.** Twilio handles interactive content differently, so Soneka shows a numbered text menu and reads the number the customer types. Flows stay fully usable on Twilio.
* **WhatsApp Form is Cloud API only.** The step does nothing on the Unofficial API or Twilio; it needs a published WhatsApp Form.
* **Google steps need the Google connection.** Connect Google (the same one used for Calendar and appointments) before using Sheets, Docs, Form, or Meet.
* **Branding footer.** If your plan adds a branding footer, it's automatically appended to outgoing text and interactive messages (templates excepted).

***

## Manage Flows

* **Duplicate.** Copies a flow as a fresh **draft** (titled with `(Copy)`) so you can iterate without touching the live version.
* **Pause / Resume.** A paused flow stops enrolling new contacts but keeps its design.
* **Publish / Unpublish.** Publishing makes the flow live; unpublishing returns it to draft.
* **Delete.** Removes the flow. Flows belong to your workspace; teammates in the same workspace can manage them.
* **Filter.** The list filters by status (live / paused / draft), category, and name, and highlights your most-used flows.
* **Plan limits.** Your plan sets how many flows you can create. Editing existing flows doesn't count against the limit.

***

## Troubleshooting

| Symptom                                                     | Likely cause & fix                                                                                                                                 |
| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Contacts aren't being enrolled by a tag/group trigger       | The flow must be both **published and active**, and the trigger's tag/group must match. Save the flow again after editing the trigger.             |
| Subscriber shows **failed** — *"No connected device"*       | No active number in the workspace when the flow tried to launch. Connect a number (or pick one on the trigger) and enroll again.                   |
| Subscriber failed — *"Contact has no usable mobile number"* | The contact has no valid phone. Fix the contact, then enroll again.                                                                                |
| Subscriber failed — connection / server error               | The flow engine couldn't be reached. Confirm it's set up and running in admin settings.                                                            |
| Buttons / list show as a numbered text menu                 | Expected on Twilio. The customer types the number and it routes to the right branch.                                                               |
| The `abandoned` branch never fires                          | Connect the `abandoned` branch on the commerce step — an unconnected branch just ends the flow. Also confirm a wait time is set.                   |
| WhatsApp Form step does nothing                             | It is Cloud API only and needs a **published** WhatsApp Form. Publish the form first.                                                              |
| AI generate / AI step fails                                 | The provider must be enabled by your admin. Pick an enabled provider/model, or contact your admin. If it reports "no workspace", refresh the page. |
| Flow times out mid-conversation                             | Steps that wait for a reply give the customer 1 hour. If they don't respond in time the conversation ends — they'll need to start the flow again.  |
| Can't create another flow                                   | You've hit your plan's flow limit. Delete an unused flow or upgrade.                                                                               |

***

## Testing a Flow Before Going Live

<Steps>
  <Step title="Open Test Mode">
    In the flow editor, click **Test** in the top bar. Enter your own WhatsApp number as the test contact.
  </Step>

  <Step title="Simulate the Trigger">
    Manually fire the trigger event — send the keyword from your phone, or click **Simulate Webhook** to inject a test payload.
  </Step>

  <Step title="Step Through the Flow">
    The canvas highlights the active node in real time as your test conversation progresses. Send replies from your phone and watch the flow branch correctly.
  </Step>

  <Step title="Inspect Variables">
    The test panel shows the current value of every flow variable at each step — useful for debugging webhook responses and conditional logic.
  </Step>

  <Step title="Publish">
    Once satisfied, click **Publish**. The flow goes live immediately. You can unpublish at any time without deleting the flow.
  </Step>
</Steps>

***

## Example Use Cases

<CardGroup cols={3}>
  <Card title="Cart Abandonment Recovery" icon="cart-shopping">
    Trigger on a Shopify abandoned\_checkout webhook. Wait 1 hour, send a reminder with the cart contents and a discount code. If no purchase after 24 hours, send a final nudge. Tag purchasers so they exit the flow immediately.
  </Card>

  <Card title="OTP Delivery" icon="lock">
    Receive a webhook with a phone number and OTP code from your auth service. Use a Message node to send the OTP. Confirm delivery via webhook callback. Branch on delivery failure to retry or notify your backend.
  </Card>

  <Card title="Appointment Reminders" icon="calendar">
    Trigger on a scheduled time pulled from your booking system via webhook. Send a reminder 24 hours before. Use an Input node to let customers confirm (`1`), reschedule (`2`), or cancel (`3`). Branch each response to the appropriate action and update your backend.
  </Card>
</CardGroup>

***

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="Is there a limit to how many nodes a flow can have?">
    There is no hard node limit. Flows with 200+ nodes are supported — use the collapse feature to keep the canvas manageable. Performance is unaffected by flow size since execution is server-side and node-by-node.
  </Accordion>

  <Accordion title="Can a contact be in multiple flows at the same time?">
    By default, a contact can only be in one instance of a given flow at a time. You can override this in **Flow Settings → Allow Concurrent Instances** for use cases like appointment-reminder flows that a contact might legitimately enter multiple times.
  </Accordion>

  <Accordion title="How does the AI Reply node handle sensitive topics?">
    The AI Reply node uses the system prompt you define to constrain the model's behavior. You can explicitly instruct it to decline certain topics, escalate to a human for sensitive requests, or only answer questions within a defined scope. PII is always redacted before the prompt is sent to the model.
  </Accordion>

  <Accordion title="What happens if a Webhook node call fails?">
    The Webhook node has a configurable retry policy (0–3 retries with exponential backoff). After exhausting retries, it routes to the **On Error** output branch, which you can connect to a fallback Message node or an Assign node to hand off to a human agent.
  </Accordion>

  <Accordion title="Can I use Flow Builder without coding knowledge?">
    Yes. The visual canvas, AI Copilot, and pre-built templates mean most flows can be built without writing a single line of code. The Webhook node requires knowing your API endpoint URL and expected response structure, which a developer or no-code-savvy operator can handle.
  </Accordion>

  <Accordion title="Which plans include Flow Builder?">
    Flow Builder is available on **Growth (**$96/mo)** and above. AI Copilot (GPT-4o and Claude 3.5) and Split-test nodes require the **Pro plan ($**320/mo)**. Enterprise plans include custom AI model fine-tuning and dedicated flow review from Soneka's solutions team.
  </Accordion>
</AccordionGroup>
