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

# Node types

> The nine building blocks a flow is made of, and what each one needs configured.

A flow is a graph of nodes. Knowing what the set contains is the fastest way to know what a flow can and cannot do — because if a behaviour is not in this list, a flow cannot do it, and it belongs to the [AI agent](/agents) instead.

<Warning>
  **Seven entries are buildable on the canvas today, plus a composite shortcut.** The engine executes
  the ten node types documented on this page. Of those, `send_message`, `send_amb_primitive`,
  `wait_for_reply`, `branch_on_reply`, and `assign_to_agent` appear in the builder palette, alongside two
  entries that aren't part of that documented nine: `end`, and `integration` — six entries, one per
  connected app, all **coming soon** (see [Canvas basics](/chatbot/canvas) for what they do today, which
  is nothing). The canvas also offers a **"Message with options"** shortcut that isn't a node type of its
  own — it drops in a preconfigured `send_message` paired with a `branch_on_reply` whose fallback is
  hardcoded to `loop` with `max_retries: 2`.

  `set_conversation_attribute`, `add_label`, `conditional`, `delay` and `answer_opening_question` are fully
  implemented in the engine and run correctly — they simply cannot be added from the canvas yet. They are documented below
  because a flow created through the API can use them, and because they are what the canvas will gain
  first.
</Warning>

## Sending

<ResponseField name="send_message" type="plain text out">
  Sends text. Supports **Liquid templating**, so you can interpolate captured variables and contact
  attributes rather than sending a fixed string.

  ```liquid theme={null}
  Hi {{ contact.name }}, your order {{ order_number }} is on its way.
  ```
</ResponseField>

<ResponseField name="send_amb_primitive" type="rich Apple message out">
  Sends an Apple Messages for Business primitive. Configured with a `primitive_type` and the primitive's
  own payload. See [Channel-native nodes](/chatbot/channel-nodes).
</ResponseField>

## Waiting and branching

<ResponseField name="wait_for_reply" type="pause">
  Pauses until the customer responds. Flow execution state is persisted, so a flow can wait as long as it
  needs to — this is not an open connection held for hours.

  **The `timeout_seconds` field is coming soon.** The builder lets you set it, but nothing reads it
  today — there's no timeout job. A wait persists indefinitely until the customer replies, however long
  that takes, regardless of what you enter here.
</ResponseField>

<ResponseField name="branch_on_reply" type="route on what they said">
  Routes on the customer's reply using match clauses, with a `fallback` for anything that matches
  nothing. The fallback can loop back or escalate.

  **The fallback is the important part.** Customers say things you did not anticipate; a branch without
  a sensible fallback is where flows strand people.
</ResponseField>

<ResponseField name="conditional" type="if/else on state">
  Branches on variables rather than on a reply — what you already know, not what they just said.
  Configured with a condition and true/false next nodes.
</ResponseField>

<ResponseField name="delay" type="timed pause">
  Waits a fixed `duration_seconds` before continuing. Use sparingly — a deliberate pause can make a bot
  feel less robotic, but it is also just latency the customer experiences.
</ResponseField>

## Changing state

<Note>
  The two nodes in this section — `set_conversation_attribute` and `add_label` — run correctly in
  the engine but are **not yet in the builder palette**. A flow authored through the API can use them.
</Note>

<ResponseField name="set_conversation_attribute" type="write a value">
  Sets a `key` to a `value` on the conversation, with Liquid support in the value. This writes a
  **conversation attribute** — not an entry in the execution's variable bag.

  **Reading it back through `{{ variables.<key> }}` is coming soon.** Liquid's `variables` scope is
  populated only by `last_reply`, the trigger, and two internal counters the engine writes — nothing
  `set_conversation_attribute` writes reaches it yet, so a later node's `{{ variables.<key> }}` will not
  resolve a value you captured here. See [Captured variables and Liquid](/chatbot/branching) for exactly
  what `variables` exposes today.
</ResponseField>

<ResponseField name="add_label" type="tag it">
  Applies a label to the conversation. Labels feed [automation](/automation) and reporting, so this is
  how a flow hands context to everything downstream.
</ResponseField>

## Answering

<ResponseField name="answer_opening_question" type="hand the opening message to the AI">
  Hands the customer's opening message to the [AI agent](/agents) once, so a flow can welcome a customer
  and still answer the question they started with. A bare greeting such as "hi" gets nothing extra, and an
  answer leaves the flow running.

  It only acts on Apple Messages conversations where the account setting `answer_opening_question` is on
  and the AI agent is available; otherwise it passes through and the flow carries on. It is backend-only
  for now, with no builder UI, so a flow created through the API is the only way to use it.

  Place it right before the first `wait_for_reply`. The answer is sent after the messages the flow already
  sent, but the nodes after this one are not held back while the AI works. If the AI escalates to a person,
  the flow ends. No flow starts while a person owns the conversation, so after the handoff the customer's next message does not start this flow or any other. If the conversation is resolved and the customer later writes again, the conversation is no longer person-owned, so a flow can start again (an initial flow only if it is marked to restart on reopen). A takeover that is still active keeps it person-owned. The customer's opening message is not treated as
  a reply to the flow's own question, so it does not feed `branch_on_reply`.
</ResponseField>

## Ending

<ResponseField name="assign_to_agent" type="hand to a human">
  Escalates. Three strategies: `round_robin_inbox`, `specific_agent`, or `team`.

  **`round_robin_inbox` is coming soon.** It's a no-op stub today — selecting it sets the assignee to
  nobody. Only `specific_agent` and `team` actually assign an agent — use one of those two until round
  robin ships.

  Once a human messages the customer, the resolution is **not billable at all** — see
  [AI-to-human handoff](/inbox/handoff).
</ResponseField>

A flow also terminates implicitly, either completed or escalated.

## Not yet available

<Warning>
  **There are no outbound-webhook or HTTP-fetch nodes.** A flow cannot currently call an external
  service, either to push data out or to fetch data in mid-flow. Both were specified and neither is
  built.

  If your flow needs to read from or write to an external system, that work belongs to the
  [AI agent](/agents), which reaches connected systems through integrations — and which is what
  determines the [resolution class](/pricing/resolution-pricing) in any case.
</Warning>

This is the single most common thing people expect a flow to do that it cannot. Worth knowing before you design around it.

## Choosing between a flow and the agent

| If you need… | Use |
| - | - |
| The same sequence every time | A **flow** |
| To read or write an external system | The **agent** |
| To handle a question you did not anticipate | The **agent** |
| A compliance script worded exactly | A **flow** |
| To collect a few specific things in order | A **flow** |
| To decide what to do based on context | The **agent** |

## Next

<CardGroup cols={2}>
  <Card title="Branching and variables" icon="split" href="/chatbot/branching">
    Conditions, captured variables and Liquid.
  </Card>

  <Card title="Channel-native nodes" icon="sparkles" href="/chatbot/channel-nodes">
    Which AMB primitives a flow can emit.
  </Card>

  <Card title="Testing and simulation" icon="flask-conical" href="/chatbot/testing">
    Running the graph before a customer does.
  </Card>

  <Card title="AI agents" icon="bot" href="/agents">
    Everything the node set deliberately does not cover.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.