# Replace a flow's draft

`PUT https://api.morevoice.ai/v1/flows/{id}/draft`

Replaces the draft graph. Nodes are matched to the stored ones by `id`: what the v1 schema does not carry (groups, notes, editor state) is kept, and `internal` nodes stay exactly as stored. `base_rev` must be the draft's current revision, else 409 (details.draft_rev) and nothing is written — read the draft again and retry. Calls keep running the published version until you publish.

Authenticate with a secret API key: `Authorization: Bearer $MOREVOICE_API_KEY`.

Operation ID: `flows_update_draft`.

## Parameters

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `string` | yes | A flow ID (`flow_…`). |

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `MoreVoice-Version` | `string` | no | The API version to use for this request. Defaults to the version the API key is pinned to. |

## Request body

Required, `application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `graph` | `FlowGraphParamsInput` | yes | A whole graph to write. Nodes are matched to the stored draft by `key`. |
| `graph.nodes` | `FlowNodeParamsInput[]` | yes | — |
| `graph.kind` | `"voice" \| "agent_script" \| "ivr"` | no | Must be the flow's kind (default: the flow's). |
| `graph.schema_version` | `1` | no | — |
| `graph.settings` | `object` | no | Merged with the stored settings. |
| `graph.variables` | `object[]` | no | Default: the stored variables. |
| `base_rev` | `integer` | yes | The draft `rev` you read: a newer draft (changed elsewhere) answers 409 and nothing is written. |

Example:

```json
{
  "base_rev": 17,
  "graph": {
    "nodes": [
      {
        "key": "start",
        "start": {
          "greeting": "Hello!"
        },
        "transitions": [
          {
            "condition": {
              "kind": "always"
            },
            "next": "bye"
          }
        ],
        "type": "start"
      },
      {
        "end": {
          "message": "Goodbye."
        },
        "key": "bye",
        "type": "end"
      }
    ]
  }
}
```

## Responses

### 200 OK

OK Returns `FlowDraft`.

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_draft"` | — |
| `flow_id` | `string` | A flow ID (prefix `flow_`). |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `rev` | `integer` | Send as `base_rev` on the next write. |
| `graph` | `FlowGraph` | A flow's graph: nodes (v1 node schema) wired by their transitions' `next`, variables and settings. |
| `graph.schema_version` | `1` | The node schema version (1). |
| `graph.kind` | `"voice" \| "agent_script" \| "ivr"` | — |
| `graph.nodes` | `FlowNode[]` | — |
| `graph.variables` | `object[]` | — |
| `graph.settings` | `object` | — |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

Example:

```json
{
  "flow_id": "flow_7Kp1Ns4Vy6Ab9Dg2Hj5Lm8",
  "graph": {
    "kind": "voice",
    "nodes": [
      {
        "disabled": false,
        "global": null,
        "key": "start",
        "position": {
          "x": 0,
          "y": 0
        },
        "start": {
          "first_message_mode": "speak",
          "greeting": "Hello, you've reached Acme.",
          "interruptible": true
        },
        "title": "Start",
        "transitions": [
          {
            "condition": {
              "kind": "always"
            },
            "key": "t_next",
            "label": "Next",
            "next": "ask_id"
          }
        ],
        "type": "start"
      },
      {
        "disabled": false,
        "global": null,
        "key": "ask_id",
        "position": {
          "x": 320,
          "y": 0
        },
        "question": {
          "confirm": true,
          "max_retries": 2,
          "prompt": "What is your ID number?",
          "reask_prompts": [],
          "var": "customer_id"
        },
        "title": "Ask for the ID",
        "transitions": [
          {
            "condition": {
              "kind": "outcome",
              "outcome": "collected"
            },
            "key": "t_ok",
            "label": "Collected",
            "next": "bye"
          },
          {
            "condition": {
              "kind": "outcome",
              "outcome": "max_retries"
            },
            "key": "t_fail",
            "label": "Couldn't collect",
            "next": "bye"
          }
        ],
        "type": "question"
      },
      {
        "disabled": false,
        "end": {
          "message": "Thank you, goodbye."
        },
        "global": null,
        "key": "bye",
        "position": {
          "x": 640,
          "y": 0
        },
        "title": "Goodbye",
        "transitions": [],
        "type": "end"
      }
    ],
    "schema_version": 1,
    "settings": {
      "classifier_model": null,
      "fallback_node_key": null,
      "global_prompt": "You are Acme's friendly receptionist.",
      "ivr": null,
      "language": "en",
      "max_chain_steps": 25,
      "max_transitions": 200,
      "max_turns_per_node": 8,
      "max_visits_per_node": 5,
      "on_pre_call_fail": "continue",
      "pre_call_timeout_ms": 2500,
      "style_field": "auto",
      "transition_model": "inline"
    },
    "variables": [
      {
        "key": "customer_id",
        "label": "Customer ID",
        "source": "collected",
        "type": "text"
      }
    ]
  },
  "livemode": true,
  "object": "flow_draft",
  "rev": 17,
  "updated": "2026-11-03T09:14:22.000Z"
}
```

### 400 Bad Request

The request is invalid: a parameter is missing, malformed or unknown, or the version header is unknown. Returns `ErrorEnvelope`.

### 401 Unauthorized

No valid API key was sent. Returns `ErrorEnvelope`.

### 403 Forbidden

The key may not do this (a missing scope, a plan limit, or a compliance block). Returns `ErrorEnvelope`.

### 404 Not Found

No object with this ID exists in this organisation and mode. Returns `ErrorEnvelope`.

### 429 Too Many Requests

Too many requests, or no call capacity right now. Retry after the Retry-After delay. Returns `ErrorEnvelope`.

### 500 Internal Server Error

Something went wrong on MoreVoice's side. Retry with the same Idempotency-Key. Returns `ErrorEnvelope`.

## Code samples

**TypeScript**

```ts
import MoreVoice from "@morevoice/sdk";

const mv = new MoreVoice(); // MOREVOICE_API_KEY from the environment

const flowDraft = await mv.flows.updateDraft("flow_7Hk2Lm9Qp", {
	base_rev: 17,
	graph: {
		nodes: [
			{
				key: "start",
				start: {
					greeting: "Hello!",
				},
				transitions: [
					{
						condition: {
							kind: "always",
						},
						next: "bye",
					},
				],
				type: "start",
			},
			{
				end: {
					message: "Goodbye.",
				},
				key: "bye",
				type: "end",
			},
		],
	},
});
console.log(flowDraft);
```

**Python**

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_draft = client.flows.update_draft("flow_7Hk2Lm9Qp", {
    "base_rev": 17,
    "graph": {
        "nodes": [
            {
                "key": "start",
                "start": {
                    "greeting": "Hello!",
                },
                "transitions": [
                    {
                        "condition": {
                            "kind": "always",
                        },
                        "next": "bye",
                    },
                ],
                "type": "start",
            },
            {
                "end": {
                    "message": "Goodbye.",
                },
                "key": "bye",
                "type": "end",
            },
        ],
    },
})
print(flow_draft)
```

**cURL**

```sh
curl -X PUT https://api.morevoice.ai/v1/flows/flow_7Hk2Lm9Qp/draft \
  -H "Authorization: Bearer $MOREVOICE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "base_rev": 17,
  "graph": {
    "nodes": [
      {
        "key": "start",
        "start": {
          "greeting": "Hello!"
        },
        "transitions": [
          {
            "condition": {
              "kind": "always"
            },
            "next": "bye"
          }
        ],
        "type": "start"
      },
      {
        "end": {
          "message": "Goodbye."
        },
        "key": "bye",
        "type": "end"
      }
    ]
  }
}'
```
