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

# Workflow Definition Schema

> 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. Use this contract for workflow agents. Retrieve an existing definition before editing it and preserve fields you are not changing. Validate and test changes before publishing.

```json theme={null}
{
  "nodes": [],
  "edges": []
}
```

***

## Nodes

Each node represents a step in the conversation.

```json theme={null}
{
  "id": "uuid-string",
  "type": "agentNode",
  "position": { "x": 100, "y": 200 },
  "data": { "name": "Support", "prompt": "Help the caller with their request." }
}
```

| 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`    | URL for API-triggered outbound phone calls          |
| `webhook`    | Sends an HTTP request after the run completes       |
| `qa`         | Runs quality analysis on the completed call         |

***

## Node data fields

### Conversation node fields

| Field                            | Type    | Default  | Description                                                    |
| -------------------------------- | ------- | -------- | -------------------------------------------------------------- |
| `name`                           | string  | required | Display name for the node                                      |
| `prompt`                         | string  | required | Instructions for Start Call, Agent, Global, and End Call 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 theme={null}
{
  "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_use_workflow_llm`  | boolean        | `true`  | Use the agent's LLM for analysis                                                                                 |
| `qa_llm_configuration` | object or null | `null`  | Separate analysis connection when `qa_use_workflow_llm` is false; preserve the configuration returned by the API |
| `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 theme={null}
{
  "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
* A workflow needs exactly one start node; an API Trigger does not replace the Start Call conversation step
* Use at most one Global node; multiple End Call nodes can represent different endings
* Validate with the agent validation endpoint before publishing

***

## Minimal example

```json theme={null}
{
  "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"
      }
    }
  ]
}
```
