Skip to content
Last updated

A Flow is a conversation graph that belongs to a single Agent. It defines how the agent reacts to user input: which questions to ask, which AI behavior to run, which external API to call, which conditions to branch on.

Flows are agent-scoped. They are not reusable across agents — clone or recreate them if you need a similar shape elsewhere.

Identity

FieldTypeNotes
idnumberUse as flowId in nested routes.
namestringDisplay name.
descriptionstring?
statusenumACTIVE · DRAFT · PAUSED · ARCHIVED.
runCountnumberTotal executions.
assistantIdstringOwning agent (always returned in detail).
isDefaultbooleanOne flow per agent is the default entry point.
liveSnapshotIdstring?MongoDB ObjectId of the published snapshot.
draftSnapshotIdstring?ObjectId of the working draft.
createdAtstringISO timestamp.
updatedAtstringISO timestamp.

The graph

A flow's behavior lives in its graph: a set of nodes connected by edges.

Node types

TypePurpose
STARTEntry point. Every flow has exactly one.
TRIGGER_INTENTBranches the conversation when an Intent matches.
SAY_AISends a message. Optionally generated by the AI model.
RESPONSE_AICaptures the user's free-text answer guided by instructions.
TOOLS_AILets the AI decide which custom Tool to call (incl. table tools).
APICalls an external HTTP endpoint and stores the result.
CONDITIONAL_ROUTINGBranches based on AI-evaluated conditions over the context.
CREATE_RECORD_ACTIVITYLogs a manual activity (note, call, meeting, email, WhatsApp) on a specific Object record.

The DYNAMIC_TABLES ("Data Action") node is automation-only and is not available in flows. To read/write records inside a flow, use a TOOLS_AI node with table tools.

Each node has a stable nodeId (regex [a-zA-Z0-9_-]+_\d+), an alias, a position for the canvas, and a data payload whose shape depends on type.

Edges

Edges connect a node's handle (output port) to another node's targetEdge (input). The same edge object lives both inline on the node and as a global list — the API normalizes both on write.

Reference validation: on create/update, the API validates every cross-resource reference inside a node's data payload — intentIds (TRIGGER_INTENT), customToolIds / playbookIds / selectedRecordTypes[].id (TOOLS_AI), assistantId (RESPONSE_AI), aiModelId, knowledgeBaseIds, etc. If any referenced id does not exist or does not belong to your account, the request returns 400 bad_request with details.issues[].code === "not_found" and no partial state is persisted. See Errors.

Snapshots

When you publish a flow, the draft snapshot is promoted to the live snapshot. The agent serves traffic from liveSnapshotId. Mutations via POST /nodes, PUT /nodes/{nodeId}, POST /edges, etc. write to the draft.

The Start flow & triggering

  • Default Start flow. Every agent ships with a default flow named "Start" (in DRAFT) containing a single START node. It runs automatically at the beginning of every conversation — first-contact logic (greeting, capturing data, creating a record) belongs here, added after the START node. It's the flow with isDefault: true.
  • The START node is unique. Only the default Start flow may contain a START node; the API rejects a START node in any other flow with 400.
  • Other flows are triggered. A non-default flow begins with a TRIGGER_INTENT node and is entered when it matches the user, configured by either:
    • IntentsintentIds on the TRIGGER_INTENT node; the flow fires when the user's message matches one of them.
    • Agentic routingagenticRouting, a natural-language instruction describing when to enter the flow; the agent routes based on it and the user's intention.
  • Default-message rule. If a flow finishes a turn without producing a user-facing message (e.g. it only captured variables or ran a Dynamic Tables action), the agent sends a default AI-generated message so the user always receives a reply. This applies to every flow.

Variable interpolation

Text fields can reference variables as {VARIABLE_NAME}. The name must match exactly (case-sensitive). Interpolable fields include:

  • API node: url, headers[].value, parameters[].value, body.
  • Say AI: message, prompt.
  • Response AI: instructions.
  • Tools AI: instructions.
  • Conditional Routing: conditions[].expression.
  • Dynamic Tables: rowId, search, rowData values.
  • Create Record Activity: rowId, content.

See Flow Variables.

Capturing values into variables

Interpolation reads a variable; capturing writes one. The field that populates a variable depends on the node type:

NodeFieldItem shape
Tools AI / Response AI / AI CapturecaptureVariablesreference an existing variable
APIvariables{ key, value, fullResponse }key names an existing variable, value is a path into the JSON response

Capture targets must reference a variable that already exists. Create it first (POST /agents/{agentId}/variables for flows, POST /workflows/{workflowId}/variables for automations). In captureVariables you may pass just { "name": "<var>" } (or { "id": <id> }) — the API resolves it and stores the canonical { id, name, description } so it is linked and rendered in the app. An unknown name/id (or an API variables[].key that doesn't exist) returns 400.

Captured values are matched by name, so an AI node and an API node can write to the same {name}. The two node families use different fields (captureVariables vs variables); the wrong field on a node is silently ignored.

API node response paths (value)

For an API node, value is a property path into the parsed JSON response — simple property access, not JSONPath (no $, wildcards, or filters):

  • Dot notation for nested objects: data.user.email.
  • [n] for array indices: data.items[0].id ([0] is equivalent to .0; a leading dot is optional).
  • Empty value, or fullResponse: true, captures the whole response body.

For the response {"data":{"items":[{"id":42,"price":9.99}],"total":1}}:

valueCaptured
data.total1
data.items[0].id42
data.items[0].price9.99

Path extraction only applies when the response body is JSON. If a step in the path is missing or null, the variable is left unset (no error). Captured objects/arrays are stored as a JSON string; primitives as their string value.

CREATE_RECORD_ACTIVITY node

Logs a manual activity on a specific Object record during a conversation flow.

{
    "nodeId": "node_create_activity_1",
    "type": "CREATE_RECORD_ACTIVITY",
    "position": { "positionX": 640, "positionY": 0 },
    "data": {
        "type": "CREATE_RECORD_ACTIVITY",
        "recordTypeId": 5,
        "rowId": "{contact_row_id}",
        "activityType": "NOTE",
        "content": "El usuario preguntó sobre: {user_question}"
    }
}
FieldRequiredNotes
recordTypeIdNumeric id of the Object's record type. Validated: must exist in your account.
rowIdMongoDB ObjectId of the record. Supports {varName} interpolation.
activityTypeNOTE, EMAIL, PHONE_CALL, MEETING, or WHATSAPP. Validated at save time.
contentActivity body text. Supports {varName} interpolation.

Variables in rowId and content must exist — the API returns 400 if any {varName} is unknown.

Operations

VerbPathPurpose
GET/public/v1/agents/{agentId}/flowsList flows
POST/public/v1/agents/{agentId}/flowsCreate
GET/public/v1/agents/{agentId}/flows/{flowId}Detail (?includeNodes=true for nodes)
PUT/public/v1/agents/{agentId}/flows/{flowId}Update metadata / status
DELETE/public/v1/agents/{agentId}/flows/{flowId}Soft delete
GET/public/v1/agents/{agentId}/flows/{flowId}/graphFull graph (nodes + edges)
POST/public/v1/agents/{agentId}/flows/{flowId}/nodesCreate node
PUT/public/v1/agents/{agentId}/flows/{flowId}/nodes/{nodeId}Update node
DELETE/public/v1/agents/{agentId}/flows/{flowId}/nodes/{nodeId}Delete node + incident edges
POST/public/v1/agents/{agentId}/flows/{flowId}/edgesAdd/replace edge
DELETE/public/v1/agents/{agentId}/flows/{flowId}/edgesRemove edge

CLI

frontline agents flows list --table
frontline agents flows create --name "Order Routing"
frontline agents flows nodes create --data '{"nodeId":"start_1","type":"START","position":{"positionX":0,"positionY":0}}'
frontline agents flows edges add --source start_1 --source-handle default --target say_1 --target-handle default