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

# Step Types

> The nine steps of a Chat Center Workflow, and every field

## At a glance

| Step | Does | Exits |
| - | - | - |
| [Start](#start) | Where every message begins | 1 |
| [Run code](#run-code) | Runs your Python; keeps what it returns | 2 — success, failure |
| [Condition](#condition) | Picks the first rule that holds | one per rule, plus Otherwise |
| [Update contact](#update-contact) | Saves values on the contact | 1 |
| [Send text](#send-text) | Sends a message | 1 |
| [Send template](#send-template) | Sends an approved WhatsApp template | 1 |
| [Send media](#send-media) | Sends an image, video, audio or document | 1 |
| [Send buttons](#send-buttons) | Sends reply buttons or a list | 1 |
| [Assign chat agent](#assign-chat-agent) | Hands the message to a Basic or Advanced agent | none — the run ends |
| [End](#end) | Ends the run | none |

Anything can follow anything — a code step after a send is fine. An exit left unconnected ends the run there. The workflow cannot loop back on itself: every message has to reach an end.

***

## Start

Every message begins here. Connect it to the first step.

***

## Run code

Your Python, written in the step: `async def run()`, returning a dict. It can call your APIs, read the chat and the contact, and save values on the contact. What it returns is kept under the step's **result key** for every later step.

| Field | |
| - | - |
| **Result key** | The name later steps read the result by: `{{classify.intent}}` |
| **Timeout** | Seconds, up to 30 (default 10) |
| **Code** | The Python, with **Generate with AI**, **Verify**, **Test** and the **i** guide |
| **Success** / **Failure** | Where to go. Failure: the code returned `{"status": "error", ...}`, raised, broke a code check, or ran out of time |

See [Run code steps](/chat-agents/workflow/code-steps).

***

## Condition

One or more rules, then **Otherwise**. Checked top to bottom by code; the first that holds wins. A rule reads a code result, a contact attribute, the message itself (its text, type, tapped button) or a count over the chat, and compares it — equals, contains, has any of these words, matches a pattern, greater than… See [Conditions](/chat-agents/workflow/conditions).

***

## Update contact

Saves values on the contact's CRM record. Each row is an **attribute** (from **Contacts → Attributes**) and a **source**: a fixed value, another contact attribute, a code result or the message. Later steps see the new values. In Test Chat nothing is written.

***

## Send text

One WhatsApp message, sent word for word. It can hold values filled in when it is sent:

| In the text | Becomes |
| - | - |
| `{{contact.first_name\|there}}` | a contact attribute, with a default |
| `{{message.text}}` | what the user wrote |
| `{{pay.link}}` | the `link` field of the code step whose key is `pay` |

***

## Send template

An approved WhatsApp template — the one kind of message WhatsApp delivers outside the 24-hour window. Every variable gets a source (fixed, contact attribute, code result or the message); a media header has an **Upload** button. **Track link clicks** for templates with URL buttons.

***

## Send media

An image, video, audio clip or document. The link is a source — upload a file for a permanent link, or take it from a code result. Documents have a file name; everything but audio can have a caption.

***

## Send buttons

A message with up to 3 reply buttons, or a list of up to 10.

| Field | |
| - | - |
| **Message text** | With `{{...}}` values |
| **Buttons** | Each with its text (24 characters), an **id**, and an optional description for lists |
| **Footer**, **List button** | Optional |

The buttons are **not branches**. A tap comes back as the user's **next message**, which runs the workflow again from Start with the button's id in it. Branch on it with a Condition near the start: *The message → Tapped button id* equals `buy`.

***

## Assign chat agent

Hands the message to one of your **Basic or Advanced WhatsApp agents**, which replies with its own model at its **published** version. The run ends here; anything the workflow sent first goes out before the agent's reply.

| Field | |
| - | - |
| **Chat agent** | Any Basic or Advanced WhatsApp agent of the account. Publishing the workflow checks it exists and is published |
| **Note for the agent** | Optional, with `{{...}}` values — added to the agent's context for this message, e.g. `intent={{classify.intent}}` |

The agent's replies are stored as its own, so its follow-ups, billing and reports work as if the number were its own.

***

## End

Ends the run. Anything sent before it still goes out. Ending without sending anything is how a workflow stays quiet — on a flood of repeated messages, for example.


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