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

# Bot Flows

> Build multi-step WhatsApp conversations visually — messages, buttons, media, list pickers, API calls, and AI handoff.

A **Bot Flow** is Xobito's most powerful automation. Instead of a single reply, a flow is a graph of connected nodes: the customer messages you, the flow runs start to finish, and along the way it can send text, images, list pickers, button menus, call an external API, hand over to an AI assistant, and more.

<Note>
  Flows execute **linearly** when triggered — once a trigger matches, every connected node runs in order. Branching happens where a customer taps a button: each button on a Button Message node is a separate output handle that can lead to a different downstream node.
</Note>

If you want the full list of what every node does, jump to the [Bot Flow Nodes reference](/automations/bot-flow-nodes).

## When to reach for a Bot Flow

Pick a Bot Flow over a [Message Bot](/automations/message-bots) or [Template Bot](/automations/template-bots) when you need one or more of:

* A conversation with more than one step.
* Buttons that lead to **different** outcomes (not just the same reply).
* Media — images, video, audio, documents, stickers.
* A WhatsApp list picker with multiple sections.
* A location pin or a contact card.
* An API call to a service you operate (CRM, order system, knowledge base).
* Handover to an AI Assistant.

If you don't need any of those, a Message Bot is usually easier to maintain.

## Open the builder

Go to **Automations → Bot Flows**.

* Click **Create Flow** to start a new one.
* Click any row to open the visual builder and edit an existing flow.

Every flow has:

| Field           | Limit           | Purpose                                    |
| --------------- | --------------- | ------------------------------------------ |
| **Name**        | 255 characters  | Internal — customers never see it.         |
| **Description** | 1000 characters | Optional note about what the flow does.    |
| **Active**      | on / off        | When off, the flow is saved but won't run. |

<Note>
  Flows do not have a draft state. As soon as the flow is saved **and** active, it runs on matching incoming messages. Keep a flow inactive while you're still editing.
</Note>

## How a flow runs

When a message comes in:

1. Xobito compares the message against every **active** flow's Trigger node.
2. The first matching flow wins — its nodes execute one after another, following the edges from the Trigger.
3. At a Button Message, the flow **pauses** and waits for the customer to tap a button. The tap determines which edge runs next.
4. The flow ends when it reaches a node with no outgoing edge.

A single flow run is short-lived and stateless — there's no timer, no "wait 2 hours then continue", no persistent memory between nodes. For that kind of logic, chain multiple flows and triggers.

## The trigger

Every flow starts with exactly one **Trigger** node. It's created for you when you start a new flow.

The Trigger defines two things — **who** this flow applies to and **when** it fires:

| Field           | Values                                                                                                   |
| --------------- | -------------------------------------------------------------------------------------------------------- |
| **rel\_type**   | `lead` or `customer` — the contact type the flow applies to.                                             |
| **reply\_type** | `1` on exact match, `2` message contains, `3` on first message, `4` fallback (no other keyword matched). |
| **trigger**     | Comma-separated keywords. Required for reply types 1 and 2. Ignored for 3 and 4.                         |

These are the same four reply types used everywhere in Xobito automations.

<Tip>
  Reply type 4 ("fallback") is the closest thing to a "default" flow — it runs when no other bot caught the customer's message.
</Tip>

The Trigger has a single output — it can connect to exactly one next node.

## The 10 node types

Inside the builder, after the Trigger you can add any combination of these nine action nodes:

<CardGroup cols={2}>
  <Card title="Text Message" icon="message">
    Send a plain text reply. Up to 1000 characters.
  </Card>

  <Card title="Button Message" icon="square-caret-down">
    Send text with up to 3 quick-reply buttons. **This is how flows branch.**
  </Card>

  <Card title="Call To Action" icon="arrow-up-right-from-square">
    Send text with a URL button that opens a link.
  </Card>

  <Card title="List Message" icon="list">
    Send a WhatsApp list picker with up to 10 sections.
  </Card>

  <Card title="Media Message" icon="image">
    Send an image, video, audio, document, or sticker.
  </Card>

  <Card title="Location" icon="location-dot">
    Send a pin with latitude, longitude, name, and address.
  </Card>

  <Card title="Contact Card" icon="address-card">
    Send one or more vCard contacts.
  </Card>

  <Card title="API Request" icon="plug">
    Call an external HTTP endpoint mid-flow.
  </Card>

  <Card title="AI Personal Assistant" icon="robot">
    Hand the conversation over to an AI Assistant (if the module is enabled).
  </Card>
</CardGroup>

For every parameter on every node, see the [Bot Flow Nodes reference](/automations/bot-flow-nodes).

<Note>
  Only the AI Personal Assistant node is conditional — it appears in the builder only if the AI Assistant module is enabled on the workspace. All other nodes are always available.
</Note>

## How branching works

Bot Flows branch on a **Button Message** node. Each button you define (up to three per Button Message) is a separate output handle — `button-0`, `button-1`, `button-2` in the underlying graph. Connect an edge from each handle to a different downstream node, and the flow picks a path based on which button the customer tapped.

```
[Trigger] → [Button Message: "How can we help?"]
                ├── button-0: "Sales"   → [Text Message: pricing info]
                ├── button-1: "Support" → [List Message: ticket categories]
                └── button-2: "Hours"   → [Text Message: business hours]
```

<Warning>
  There's no dedicated Condition node in the builder. Conditional routing is done exclusively via Button Message handles. If you need "do X if custom field Y", you'll want a Button Message asking the customer directly, or an API Request node that calls your own system.
</Warning>

## Variables and merge fields

Inside any text field of any node — reply text, headers, button labels, URLs, API bodies — you can insert merge fields using **single curly braces**:

```
{lead_status}
{lead_source}
{lead_assigned}
{contact_first_name}
{contact_last_name}
{contact_id}
{contact_company}
{contact_email}
{contact_phone_number}
```

Example body text:

```
Hi {contact_first_name}, your account ID is {contact_id}.
```

<Warning>
  Flow variables use **single** curly braces: `{contact_first_name}`.
  Approved template variables use **double** curly braces: `{{1}}`, `{{2}}`.
  They are different syntaxes and can't be swapped.
</Warning>

### What is and isn't a variable

* **Predefined merge fields** (the nine above) — supported everywhere.
* **Custom fields** you've defined on contacts — **not currently** usable as merge fields inside flows.
* **Flow-local variables** (storing "the answer the customer just gave") — **not available**. The flow has no state between nodes, so you can't capture a customer's reply into a variable and reuse it later. If you need that, use an API Request to push the data to your own system.

## Validation and limits

When you save a flow, Xobito checks:

| Rule                         | Details                                                                                                                                                                             |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Orphan nodes**             | Every node except the Trigger must have at least one incoming edge. Orphan nodes are rejected.                                                                                      |
| **Required fields per node** | For example Text Message must have reply text; Button Message must have at least one button; Trigger must have a reply type.                                                        |
| **Per-field limits**         | Reply text up to 1000 chars, header up to 60, buttons up to 20, list items capped at 10 per section and 10 items total, etc. See the [node reference](/automations/bot-flow-nodes). |
| **Flow name**                | Max 255 characters.                                                                                                                                                                 |
| **Flow description**         | Max 1000 characters.                                                                                                                                                                |

There is **no enforced maximum** on the number of nodes per flow. Keep flows short and focused — long flows are painful to test.

## Activation

A flow runs only when **both** conditions are true:

1. The `is_active` toggle is on.
2. The flow is saved (no unsaved edits).

There's no staging, no test mode, and no version history. Once active, the next incoming message that matches the trigger will run the flow as-is.

<Warning>
  There's no built-in "test run" simulator. The only way to try a new flow is to deactivate it, finish editing, activate it, and message your own WhatsApp number. Turn it off again before real customers hit it if you're not ready.
</Warning>

## Execution order vs other automations

When a message arrives, Xobito evaluates automations in this order:

1. **Bot Flows** — first match wins.
2. **Message Bots** — only checked if no flow matched.
3. **Default greeting / away message** — only checked if neither of the above fired.

If a Message Bot you expect to fire isn't firing, check whether an active Bot Flow is catching the same keyword first.

## Where flows are stored

Each flow is stored as a single row in the `bot_flows` table on your tenant database. The visual graph is serialised into a `flow_data` JSON column. You don't normally need to know this, but it explains two useful things:

* **Exporting / importing flows** happens by copying the JSON blob.
* **Each tenant has their own flows** — flows never leak across workspaces.

## Permissions

| Permission               | Allows                                                |
| ------------------------ | ----------------------------------------------------- |
| `tenant.bot_flow.view`   | See the Bot Flow list and open the builder read-only. |
| `tenant.bot_flow.create` | Create new flows.                                     |
| `tenant.bot_flow.edit`   | Edit existing flows and change the active toggle.     |
| `tenant.bot_flow.delete` | Delete a flow.                                        |

The workspace owner has all four automatically.

## Feature availability

Bot Flows require the `bot_flows` feature on your subscription. If the link is missing from the sidebar, your plan doesn't include them.

## Good practice

<AccordionGroup>
  <Accordion title="Start with a skeleton, fill it in">
    Drop in the Trigger → Text Message → Button Message → (three buttons to three Text Messages) skeleton first. Save, activate on your own number, and walk through it. Then replace the placeholder text with real content one node at a time.
  </Accordion>

  <Accordion title="Keep flows short">
    A flow longer than 10–12 nodes becomes hard to reason about. If a flow needs to branch deeply, break it up into smaller flows that each handle one sub-topic, and chain them with a Button Message whose buttons include keywords that trigger the next flow.
  </Accordion>

  <Accordion title="Don't put secrets into API Request headers">
    The `flow_data` JSON is stored in your database. API keys you put into API Request headers live there. Prefer endpoints that don't need static secrets, or rotate the keys regularly.
  </Accordion>

  <Accordion title="Test as a real contact">
    Save your own phone number as a contact before testing. If the flow's trigger is `rel_type=lead`, make sure you're a lead, otherwise the flow won't fire on your messages.
  </Accordion>
</AccordionGroup>

## What to read next

<CardGroup cols={2}>
  <Card title="Bot Flow Nodes reference" icon="list-check" href="/automations/bot-flow-nodes">
    Every node, every parameter, every limit — with JSON examples.
  </Card>

  <Card title="Message Bots" icon="reply" href="/automations/message-bots">
    When a flow is overkill, try a keyword-to-reply bot.
  </Card>

  <Card title="Template Bots" icon="envelope" href="/automations/template-bots">
    Send an approved template on a keyword.
  </Card>

  <Card title="Activity Log" icon="clipboard-list" href="/team/activity-log">
    See who changed a flow and when.
  </Card>
</CardGroup>
