Conversation phases
A simple agent answers every turn with one prompt and one set of tools. That is enough for a single-purpose bot, but a real call has stages — greet, verify identity, answer questions, wrap up — and each stage wants different behaviour. A flow lets you express that: a graph of conversation phases, each a stretch of turns with its own configuration, wired together by edges that decide where the call goes next.
The flow graph
A flow is a graph of nodes joined by edges.
- A node is a step in the call. Every flow starts at a
startnode and finishes at anendnode; in between sit the nodes that do the work — most often conversation phases, plus utility nodes likesay,play_audio,tool_call,transfer_to_number, andagent_transfer. - An edge connects one node to the next. An edge fires on a condition:
llm_condition(the model decides the named condition is met),expression(a variable-based rule), ordefault(taken when nothing else fires).
You read and write the graph on the agent:
GET /v1/agents/{agent_id}/flow— the current flow graph.PUT /v1/agents/{agent_id}/flow— replace the agent’s draft graph. It is validated before it is stored; it does not go live until you publish.POST /v1/agents/{agent_id}/flow/publish— publish the draft as a new active flow version.GET /v1/agents/flow/schema— the JSON schema every node and edge validates against.
Drafts never touch live calls until you publish, and every publish is a version you can roll back (POST /v1/agents/{agent_id}/flow/rollback).
A flow graph is a JSON object with nodes and edges. Here is the smallest valid one — a single hosted phase between start and end. Save it as flow.json:
Set AGENT_ID and SPEECHIFY_API_KEY, then read, replace, and publish:
cURL
A conversation phase
A conversation phase (the subagent node type on the wire) is one stretch of turns run against a single brain, ending when an exit condition fires or a turn ceiling is hit. Its config carries everything that makes this stretch of the call different from the rest:
Every override is scoped to the phase. Outside it, the agent falls back to its base prompt, its full tool set, and its full knowledge scope.
Hosted and external brains
Who answers a phase is a field, not a different kind of node.
- Leave
brain_idunset and the phase runs on Speechify’s hosted model, shaped by the phase’s prompt, tool, and knowledge overrides. - Set
brain_idto an external brain — a workspace resource that names your own HTTPS endpoint — and the phase relays every turn to that endpoint. The prompt/tool/knowledge overrides do not apply — your service decides what to say. It ends its phase by replying withaction: "handoff"naming an exit condition, the same exit surface a hosted phase reaches by tool call.
Because the brain is a reference, two agents can point at the same external brain, and rotating its signing secret never requires re-saving a flow.
Exit conditions and edges
A phase ends when one of its named exit_conditions is met. Each condition maps to an outgoing llm_condition edge, so “caller verified” routes to the answering phase while “verification failed” routes to a transfer. A phase with no condition met before max_turns takes its default edge (or ends the call if there is none).
A conversation phase keeps the wire type subagent because published flows already carry it. The console and these guides call it a conversation phase.
Good to know
Variables resolve per phase, then fall through
A phase’s variables override the agent- and flow-level values only while the phase renders its instructions and first message. They are not written back to the shared store.
Publish is versioned
Every POST /flow/publish mints a version with a parent. Roll back with /flow/rollback, list history with /flow/versions, and take a flow offline with /flow/deactivate.