--- title: "Workflow Definition Schema" description: "Schema reference for the workflow_definition object used in the Agents API" --- The `workflow_definition` object passed to [Create from Definition](/api-reference/agents/create-from-definition) and [Update Agent](/api-reference/agents/update) defines the full conversation graph. It is the same structure the dashboard's visual workflow builder reads and writes — building an agent in the UI produces a `workflow_definition` under the hood, and anything you can configure visually can equally be expressed here as JSON. ```json { "nodes": [...], "edges": [...] } ``` --- ## Nodes Each node represents a step in the conversation. ```json { "id": "uuid-string", "type": "agentNode", "position": { "x": 100, "y": 200 }, "data": { ... } } ``` | Field | Type | Description | |---|---|---| | `id` | string | Unique node ID (UUID recommended) | | `type` | string | One of the node types below | | `position` | object | Visual coordinates in the workflow builder | | `data` | object | Node configuration — fields vary by type | ### Node types | Type | Description | |---|---| | `startCall` | Entry point for telephony calls | | `endCall` | Terminates the call | | `agentNode` | LLM-powered conversation step | | `globalNode` | Global configuration applied across all agent nodes | | `trigger` | Entry point for API-triggered (non-telephony) runs | | `webhook` | Sends an HTTP request when reached | | `qa` | Runs quality analysis on the completed call | --- ## Node data fields ### Common fields (all node types) | Field | Type | Default | Description | |---|---|---|---| | `name` | string | required | Display name for the node | | `prompt` | string | required* | LLM system prompt. *Not required for `trigger`, `webhook`, `qa` nodes | | `allow_interrupt` | boolean | `false` | Allow the caller to interrupt the agent mid-speech | | `wait_for_user_response` | boolean | `false` | Pause and wait for caller input before continuing | | `wait_for_user_response_timeout` | number | `null` | Seconds to wait for input before timing out | | `detect_voicemail` | boolean | `false` | Detect and handle voicemail on outbound calls | | `delayed_start` | boolean | `false` | Delay execution of this node | | `delayed_start_duration` | number | `null` | Delay in seconds | | `add_global_prompt` | boolean | `true` | Merge the `globalNode` prompt into this node's prompt | ### agentNode — data extraction | Field | Type | Default | Description | |---|---|---|---| | `extraction_enabled` | boolean | `false` | Extract structured data from the conversation | | `extraction_prompt` | string | `null` | Custom prompt to guide extraction | | `extraction_variables` | array | `[]` | Variables to extract (see below) | **Extraction variable schema:** ```json { "name": "customer_intent", "type": "string", "prompt": "What did the customer want to achieve?" } ``` `type` is one of `string`, `number`, or `boolean`. ### agentNode — tools | Field | Type | Description | |---|---|---| | `tool_uuids` | string[] | IDs of tools (HTTP API, call transfer, etc.) to attach to this node | | `document_uuids` | string[] | IDs of knowledge base documents available to this node | ### trigger node | Field | Type | Description | |---|---|---| | `trigger_path` | string | Unique UUID that becomes the API trigger endpoint path | ### webhook node | Field | Type | Default | Description | |---|---|---|---| | `enabled` | boolean | `true` | Whether this webhook fires when reached | | `http_method` | string | — | `GET`, `POST`, `PUT`, `PATCH`, or `DELETE` | | `endpoint_url` | string | — | Target URL | | `credential_uuid` | string | `null` | UUID of a stored auth credential | | `custom_headers` | array | `[]` | Additional request headers `[{"key": "...", "value": "..."}]` | | `payload_template` | object | `null` | Request body template (supports context variables) | ### qa node | Field | Type | Default | Description | |---|---|---|---| | `qa_enabled` | boolean | `true` | Enable QA analysis | | `qa_system_prompt` | string | `null` | Custom evaluation prompt | | `qa_model` | string | `null` | LLM model to use for evaluation | | `qa_min_call_duration` | integer | `15` | Minimum call duration in seconds to run QA | | `qa_voicemail_calls` | boolean | `false` | Include voicemail calls in QA | | `qa_sample_rate` | integer | `100` | Percentage of calls to analyse (1–100) | --- ## Edges Each edge connects two nodes and defines when the transition fires. ```json { "id": "edge-uuid", "source": "node-uuid-a", "target": "node-uuid-b", "data": { "label": "Customer confirms", "condition": "The customer has confirmed their appointment", "transition_speech": "Great, I've got that noted." } } ``` | Field | Type | Description | |---|---|---| | `id` | string | Unique edge ID | | `source` | string | ID of the originating node | | `target` | string | ID of the destination node | | `data.label` | string | Short label shown in the workflow builder | | `data.condition` | string | Natural language condition the LLM evaluates to trigger this edge | | `data.transition_speech` | string | Optional speech the agent says before transitioning | --- ## Validation rules - All `source` and `target` IDs in edges must reference existing node IDs - All nodes except `trigger`, `webhook`, and `qa` must have a non-empty `prompt` - Node IDs must be unique within the workflow - Each workflow must have exactly one `startCall` or `trigger` node as the entry point --- ## Minimal example ```json { "nodes": [ { "id": "start-1", "type": "startCall", "position": { "x": 0, "y": 0 }, "data": { "name": "Start", "prompt": "You are a friendly assistant. Greet the caller and ask how you can help." } }, { "id": "end-1", "type": "endCall", "position": { "x": 400, "y": 0 }, "data": { "name": "End", "prompt": "Thank the caller and say goodbye." } } ], "edges": [ { "id": "edge-1", "source": "start-1", "target": "end-1", "data": { "label": "Done", "condition": "The caller's question has been answered and they want to end the call" } } ] } ```