# Steps & nodes

> The node reference: dialogue, knowledge, webhook, notify, transfer, logic split, extract, function, keypad, wait, end — plus transition conditions, variable extraction, global nodes, and per-step tools.

Every step in a workflow is a node of one of these types, and every line between two steps carries a **transition condition** that decides when the conversation moves along it. Some steps talk; some just do a job and move on.

## Node types

| Node | What it does |
| --- | --- |
| Dialogue | The AI speaks for this step — from a per-step prompt, or **exact static wording** when the words are safety- or brand-critical. Can extract typed variables (below). |
| Knowledge | Pins reference material to the step — the menu, the price list, the policy. Only in play on this step, so long documents don't bleed elsewhere. |
| Webhook | Calls any API: method, URL, headers, body with `{{variable}}` interpolation; response values mapped back into variables via JSON paths; **conditional routes** on the result (paid → this way, failed → that way). POST `/crm/ingest` with a [Connections key](/docs/api/crm-ingest) writes a row + deal into the CRM. |
| Send a notification | Email, SMS, WhatsApp, or a help-desk ticket — see [Notifications](/docs/workflows/notifications). |
| Transfer | Hands the call to a human number, with context. On chat, hands to the help desk. |
| Transfer to workflow | Jumps to another workflow — compose big flows from small ones ("refill requests" as its own flow). |
| Logic split | Branches the moment it is reached, without speaking. Compares the variables collected so far and sends the conversation down the matching path. Always give it an **else** way out — the editor refuses to publish one without. |
| Extract a variable | Pulls named values out of what was just said and moves on without speaking. Types: text, number, yes/no, or a fixed list. |
| Function | Runs the tools attached to the step, for when calling out **is** the step — book the slot, look the order up. Nothing to say; put a dialogue step after it to read the result back. |
| Press a digit | Asks for keypresses and stores them. On a call the phone line gathers the tones; set how many digits, how long to wait, and what key ends it. Calls only. |
| Subagent | Dialogue where the AI decides **whether and when** to reach for a tool, from what the customer says. Use a function step instead when the tool must run every time. |
| Call an MCP tool | Calls one tool on an MCP server of your own. Takes the same request headers and response mapping a webhook step does; a `{{SECRET.name}}` header resolves at the moment of the call and is never logged. |
| Wait | Pauses the flow. |
| End | Closes cleanly with a final line. |

## Transition conditions

Each line leaving a step says **how** it is taken. Mixing them is normal: check what you can check, and leave the rest to judgement.

| Condition | When it is taken |
| --- | --- |
| When the model judges… | You write the condition as a sentence — *the caller said they want to book*. Judged together with the other sentence conditions, so the model picks one best match or none. |
| When the numbers say so | Rows of `variable / operator / value`, combined with **ALL** or **ANY**. No model involved. |
| Always, once they reply | Taken as soon as the caller says anything. Nothing else on that step is looked at. |
| Otherwise | The fallback, taken when nothing else matched. |
| As soon as the agent stops speaking | Moves on without waiting for a reply — for a line that needs no answer. |

### The order they are judged in

This order is fixed, and it matters: anything that can be decided for certain is decided before anything is left to the model.

1. **Always** — if the step has one, it wins outright.
2. **Equations** — top to bottom, the first one that holds.
3. **Sentence conditions** — all judged together, alongside any global step.
4. **Otherwise** — the fallback.
5. Nothing matched: the conversation stays where it is and keeps talking.

### Operators

| Operator | Compares | Behaviour |
| --- | --- | --- |
| is / is not | Text | Ignores case, and never reads text as a number — so `18` and `18.0` are different values. |
| &gt; &ge; &lt; &le; | Numbers | If either side is empty or is not a number the row is simply false. It never errors. |
| contains / does not contain | Text | Whether one value appears inside the other, ignoring case. |
| is set / is not set | Anything | Whether the variable has a value at all. An empty answer still counts as set. |

## Variables

A dialogue step or an extract step can declare typed variables — `{name}` (text), `{party_size}` (number), `{is_emergency}` (yes/no), or **a fixed list** where an answer outside the choices is refused rather than stored — and the AI extracts them from the conversation. Extracted variables flow into every later step: webhook bodies, notification wording, the deal card. Built-ins are always available: the caller's number, the time, the last user message.

## Global nodes

A **global node** listens across the whole flow, not one position in the graph. The canonical one: *"caller asks for a person"* → transfer. Wherever the conversation is, the escape works. Give every customer-facing flow at least that one.

Two settings make one behave: **go back afterwards** returns the conversation to wherever it was once your go-back condition reads true, and **stay quiet for N steps** takes the step out of the running for a while after it fires, so a customer who keeps phrasing things the same way is not bounced straight back into it.

## Per-step model

A step can name its own model. Leave it empty and the step uses the agent's. Naming a cheaper one on a routing step is how the cheap parts stay cheap while the step that matters gets something stronger.

## Worked examples

When a step words something oddly, or keeps taking the wrong way out, give it examples: a snippet of transcript, and what should have happened. Response examples steer what it says; transition examples name the step it should have reached.

## Per-step tools

Tick a [tool](/docs/ai/tools) on a step and only that step can use it — booking on the booking step, the POS push on the order step, Stripe lookup on the billing step. Tight scope is what keeps tools from firing at the wrong moment.

> **STATIC TEXT IS A FEATURE, NOT A FALLBACK:** For the shut-off instructions, the allergy disclaimer, the legal line — set the dialogue node to exact wording. The AI reads it verbatim, every time.

> **BUILD THE WHOLE THING OVER MCP:** Every node type and every transition condition can be set through `create_workflow` and `update_workflow_graph` — edges take `condition_kind`, `equation_match` and `equations`. See the [MCP tools reference](/docs/mcp/tools).
