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

# Workflows Introduction

> Build multi-step outreach sequences that combine voice agent calls, WhatsApp messages, API calls, waits and retries, driven entirely through the Bolna API.

<Note>
  Workflows are in beta. The APIs documented here are stable to build against, but details may evolve before general availability — check the [changelog](/docs/changelog/august-2026) for updates.
</Note>

## What are Workflows?

A workflow is a graph of nodes connected by routing rules — each node's ordered `cases` decide what runs next. It orchestrates a whole sequence per contact: call them, branch on whether they picked up, retry twice with a 2-minute gap if they didn't, extract what they said if they did, push the result to your CRM, and follow up on WhatsApp — each contact walking the graph independently. Running the same sequence over many contacts at once uses a [campaign](/docs/workflows/campaigns) — a concept kept deliberately separate from agent [batch calling](/docs/outbound/batch-calling), which places a single call per contact with no graph behind it.

Typical uses:

* **Lead qualification** — call, score the conversation from extracted fields, route hot leads to an API and cold leads to a WhatsApp nurture message.
* **Collections and reminders** — call, capture a promise-to-pay date, record it via your API, schedule the follow-up.
* **Unreachable-contact handling** — retry ladders with configurable gaps, then a fallback channel.

***

## Why workflows

<CardGroup cols={2}>
  <Card title="One definition, every channel" icon="layer-group">
    Calls, WhatsApp messages, HTTP calls, waits and retries live in a single graph instead of stitched-together automations across separate tools.
  </Card>

  <Card title="Safe iteration" icon="shield-check">
    Drafts are private until published, and publishing again never changes a contact already mid-run on an older version — you can keep editing without risking what's live.
  </Card>

  <Card title="Built-in retry ladders" icon="arrows-rotate">
    Configurable delayed re-attempts live inside the graph itself via the `retry` node — no separate scheduler or cron job to babysit unreachable contacts.
  </Card>

  <Card title="Full execution replay" icon="list-check">
    Every contact's path through the graph is recorded node by node with its matched case and outputs, so "why didn't this fire" has a concrete answer instead of a guess.
  </Card>
</CardGroup>

***

## The object model

<CardGroup cols={2}>
  <Card title="Workflow" icon="diagram-project">
    The named container. Holds one mutable draft and any number of immutable published versions.
  </Card>

  <Card title="Draft and versions" icon="code-branch">
    You edit the draft, then publish it as a frozen version. Runs always execute published versions — publishing again never changes anything already running.
  </Card>

  <Card title="Campaign" icon="bullhorn">
    Runs one published version over a batch of uploaded contacts. Pins its version at creation time.
  </Card>

  <Card title="Execution" icon="route">
    One contact's journey through the graph — node attempts, matched cases, and a terminal outcome.
  </Card>
</CardGroup>

The lifecycle, end to end:

```mermaid theme={"system"}
flowchart TD
    create["Create workflow"] --> save["Save draft"]
    save --> validate["Validate"]
    validate --> publish["Publish (v1)"]
    publish --> run["Run one contact<br/>POST /workflows/:id/run"]
    publish --> campaign["Create campaign<br/>upload entries → :start"]
    run --> exec["Executions<br/>poll until terminal"]
    campaign --> exec
```

***

## Nodes at a glance

| Node type          | What it does                                                                                | Branches on                                    |
| ------------------ | ------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| `start`            | Entry point; declares the contact fields and any other input variables the workflow accepts | contact data (`entry.*`)                       |
| `agent`            | Places a call with one of your Bolna agents                                                 | `call.status`, `call.duration_s`, `call.error` |
| `extraction`       | Exposes fields extracted from the preceding call                                            | `extraction.*`                                 |
| `api`              | Calls an external HTTP endpoint                                                             | `response.status`, mapped values               |
| `aisensy_whatsapp` | Sends a WhatsApp template message via AiSensy                                               | none yet — fire-and-forget, single exit        |
| `time`             | Waits for a delay or until a timestamp                                                      | single exit, no branching                      |
| `retry`            | Re-runs an earlier node on a schedule, up to N attempts                                     | evaluated once attempts are exhausted          |
| `end`              | Terminates the execution with a label and an outcome                                        | terminal                                       |

Each node routes onward through ordered **cases** — condition expressions over the execution's variables. See [Nodes](/docs/workflows/nodes) for every node's configuration, [Conditions and variables](/docs/workflows/conditions-and-variables) for the expression language, and [AiSensy WhatsApp integration](/docs/workflows/aisensy-whatsapp) for connecting an AiSensy account to the `aisensy_whatsapp` node.

***

## Authentication and conventions

All workflow endpoints live on the standard API host and authenticate with your Bolna API key:

```bash theme={"system"}
curl --location 'https://api.bolna.ai/workflows' \
--header 'Authorization: Bearer <api_key>'
```

Three conventions to know:

* **List endpoints paginate with `limit`/`offset`** and return `{items, total, limit, offset}`.
* **Errors carry a machine-readable code** in `detail.code` (for example `revision_conflict`, `duplicate_run`, `invalid_state`), with any extra context alongside it.
* **Action endpoints use a `:verb` suffix** — for example `POST /workflow-campaigns/{id}:start` — with an empty JSON body.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/docs/workflows/quickstart">
    Create, publish and run your first workflow, from the dashboard or with curl
  </Card>

  <Card title="Using the editor" icon="pen-to-square" href="/docs/workflows/using-the-editor">
    A tour of the visual canvas, toolbar and validation
  </Card>

  <Card title="Nodes" icon="circle-nodes" href="/docs/workflows/nodes">
    Every node type with its configuration and examples
  </Card>

  <Card title="Conditions and variables" icon="code-branch" href="/docs/workflows/conditions-and-variables">
    The expression language behind branching
  </Card>

  <Card title="Campaigns" icon="bullhorn" href="/docs/workflows/campaigns">
    Run a workflow over thousands of contacts
  </Card>
</CardGroup>
