# client.flows

> The flows methods of the morevoice Python SDK: Call flows: drafts, published versions and simulation.

Call flows: drafts, published versions and simulation. These methods are on `client.flows`, where `client` is a `MoreVoice` client (see [the Python SDK](https://docs.morevoice.ai/sdk/python/#connect)). On `AsyncMoreVoice` the same methods are awaited. Each one returns the response object and raises an exception when the API answers with an error.

## `create()`

**Create a flow.** Creates a flow with an empty draft, a template's, or the `graph` you send. It runs on calls once published (POST /v1/flows/{id}/publish).

```python
# client.flows
def create(self, body: _m.FlowCreateParamsInput | Mapping[str, Any], *, more_voice_version: str | Unset = UNSET, idempotency_key: str | Unset = UNSET) -> _m.Flow
```

`client.flows.create()` · `await async_client.flows.create()` · `POST /flows` · [API reference](https://docs.morevoice.ai/api/operations/flows_create/)

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `string` | yes | — |
| `assistant_id` | `string \| null` | no | `asst_…` ID. |
| `description` | `string` | no | — |
| `graph` | `FlowGraphParamsInput` | no | A whole graph to write. Nodes are matched to the stored draft by `key`. |
| `kind` | `"voice" \| "agent_script" \| "ivr"` | no | — |
| `language` | `"he" \| "en"` | no | The template's / empty flow's language (default he). |
| `template_id` | `string` | no | Start from a template instead of an empty flow. |

### Returns

`Flow`:

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | The flow's ID. |
| `object` | `"flow"` | Always `flow`. |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `name` | `string` | — |
| `description` | `string` | — |
| `kind` | `"voice" \| "agent_script" \| "ivr"` | voice: drives an AI assistant; agent_script: a human agent's branching script; ivr: a phone menu. |
| `status` | `"draft" \| "published" \| "archived"` | — |
| `published_version` | `integer \| null` | The version calls run (null: never published). |
| `latest_version` | `integer` | — |
| `draft_rev` | `integer` | The draft's revision: send it as `base_rev` when you write the draft. |
| `assistant_id` | `string \| null` | `asst_…` ID. |
| `template_id` | `string \| null` | — |
| `node_count` | `integer` | — |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow = client.flows.create({
    "kind": "voice",
    "language": "en",
    "name": "Reception",
})
print(flow)
```

## `delete()`

**Delete a flow.** Deletes the flow and its versions. 409 while an assistant or a copilot profile uses it (details list them): detach it first.

```python
# client.flows
def delete(self, id: str, *, more_voice_version: str | Unset = UNSET, idempotency_key: str | Unset = UNSET) -> _m.DeletedFlow
```

`client.flows.delete()` · `await async_client.flows.delete()` · `DELETE /flows/{id}` · [API reference](https://docs.morevoice.ai/api/operations/flows_delete/)

### Parameters

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

### Returns

`DeletedFlow`:

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | A flow ID (prefix `flow_`). |
| `object` | `"flow"` | Always `flow`. |
| `deleted` | `true` | — |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

deleted_flow = client.flows.delete("flow_7Hk2Lm9Qp")
print(deleted_flow)
```

## `duplicate()`

**Duplicate a flow.** Creates a new flow from this one's draft (unpublished, linked to no assistant).

```python
# client.flows
def duplicate(self, id: str, body: _m.DuplicateFlowParamsInput | Mapping[str, Any] | Unset = UNSET, *, more_voice_version: str | Unset = UNSET, idempotency_key: str | Unset = UNSET) -> _m.Flow
```

`client.flows.duplicate()` · `await async_client.flows.duplicate()` · `POST /flows/{id}/duplicate` · [API reference](https://docs.morevoice.ai/api/operations/flows_duplicate/)

### Parameters

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

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `string` | no | Default: the original's name with "(copy)". |

### Returns

`Flow`:

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | The flow's ID. |
| `object` | `"flow"` | Always `flow`. |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `name` | `string` | — |
| `description` | `string` | — |
| `kind` | `"voice" \| "agent_script" \| "ivr"` | voice: drives an AI assistant; agent_script: a human agent's branching script; ivr: a phone menu. |
| `status` | `"draft" \| "published" \| "archived"` | — |
| `published_version` | `integer \| null` | The version calls run (null: never published). |
| `latest_version` | `integer` | — |
| `draft_rev` | `integer` | The draft's revision: send it as `base_rev` when you write the draft. |
| `assistant_id` | `string \| null` | `asst_…` ID. |
| `template_id` | `string \| null` | — |
| `node_count` | `integer` | — |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow = client.flows.duplicate("flow_7Hk2Lm9Qp", {
    "name": "Reception B",
})
print(flow)
```

## `list()`

**List flows.** Your flows, most recently changed first (archived ones only with include_archived=true).

```python
# client.flows
def list(self, *, limit: int | Unset = 20, starting_after: str | Unset = UNSET, ending_before: str | Unset = UNSET, kind: _m.FlowsListKind | Unset = UNSET, assistant_id: str | Unset = UNSET, include_archived: _m.FlowsListIncludeArchived | Unset = UNSET, more_voice_version: str | Unset = UNSET) -> AsyncPage[_m.Flow]
```

`client.flows.list()` · `await async_client.flows.list()` · `GET /flows` · [API reference](https://docs.morevoice.ai/api/operations/flows_list/)

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | `integer` | no | How many objects to return, 1–100 (default 20). |
| `starting_after` | `string` | no | A cursor (`next_cursor`) or object ID: return the objects after it (older). |
| `ending_before` | `string` | no | A cursor or object ID: return the objects before it (newer). |
| `kind` | `"voice" \| "agent_script" \| "ivr"` | no | Only flows of this kind. |
| `assistant_id` | `string` | no | Only flows linked to this assistant. |
| `include_archived` | `"true" \| "false"` | no | Include archived flows (default false). |

### Returns

A page of results (`FlowList`): `data`, `has_more` and `next_cursor`.

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

for flow in client.flows.list():
    print(flow)
```

## `list_versions()`

**List a flow's versions.** Returns a page of `FlowVersion` objects, newest first. Pass `next_cursor` as `starting_after` for the next page; the SDKs iterate every page for you. Answers `404` with the code `resource_missing` when nothing has this ID in this organisation and mode.

```python
# client.flows
def list_versions(self, id: str, *, limit: int | Unset = 20, starting_after: str | Unset = UNSET, ending_before: str | Unset = UNSET, more_voice_version: str | Unset = UNSET) -> AsyncPage[_m.FlowVersion]
```

`client.flows.list_versions()` · `await async_client.flows.list_versions()` · `GET /flows/{id}/versions` · [API reference](https://docs.morevoice.ai/api/operations/flows_list_versions/)

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `str` | yes | A flow ID (`flow_…`). |
| `limit` | `integer` | no | How many objects to return, 1–100 (default 20). |
| `starting_after` | `string` | no | A cursor (`next_cursor`) or object ID: return the objects after it (older). |
| `ending_before` | `string` | no | A cursor or object ID: return the objects before it (newer). |

### Returns

A page of results (`FlowVersionList`): `data`, `has_more` and `next_cursor`.

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

for flow in client.flows.list_versions("flow_7Hk2Lm9Qp"):
    print(flow)
```

## `publish()`

**Publish a flow.** Publishes the draft as a new immutable version; calls start using it at once. A draft with errors is refused with 409 flow_invalid (details.issues: what to fix).

```python
# client.flows
def publish(self, id: str, body: _m.FlowPublishParamsInput | Mapping[str, Any] | Unset = UNSET, *, more_voice_version: str | Unset = UNSET, idempotency_key: str | Unset = UNSET) -> _m.Flow
```

`client.flows.publish()` · `await async_client.flows.publish()` · `POST /flows/{id}/publish` · [API reference](https://docs.morevoice.ai/api/operations/flows_publish/)

### Parameters

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

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `note` | `string` | no | What changed (shown in the version history). |

### Returns

`Flow`:

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | The flow's ID. |
| `object` | `"flow"` | Always `flow`. |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `name` | `string` | — |
| `description` | `string` | — |
| `kind` | `"voice" \| "agent_script" \| "ivr"` | voice: drives an AI assistant; agent_script: a human agent's branching script; ivr: a phone menu. |
| `status` | `"draft" \| "published" \| "archived"` | — |
| `published_version` | `integer \| null` | The version calls run (null: never published). |
| `latest_version` | `integer` | — |
| `draft_rev` | `integer` | The draft's revision: send it as `base_rev` when you write the draft. |
| `assistant_id` | `string \| null` | `asst_…` ID. |
| `template_id` | `string \| null` | — |
| `node_count` | `integer` | — |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow = client.flows.publish("flow_7Hk2Lm9Qp", {
    "note": "New opening hours",
})
print(flow)
```

## `restore.version()`

**Restore a flow version into the draft.** Copies the version's graph into the draft (a new draft revision). It is not published: publish to run it.

```python
# client.flows.restore
def version(self, id: str, version: str, *, more_voice_version: str | Unset = UNSET, idempotency_key: str | Unset = UNSET) -> _m.FlowDraft
```

`client.flows.restore.version()` · `await async_client.flows.restore.version()` · `POST /flows/{id}/versions/{version}/restore` · [API reference](https://docs.morevoice.ai/api/operations/flows_restore_version/)

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `str` | yes | A flow ID (`flow_…`). |
| `version` | `str` | yes | The version number. |

### Returns

`FlowDraft`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_draft"` | Always `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. |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_draft = client.flows.restore.version("flow_7Hk2Lm9Qp", "3")
print(flow_draft)
```

## `retrieve()`

**Retrieve a flow.** The flow's details. Its graph: GET /v1/flows/{id}/draft (editable) or /versions/{version} (published).

```python
# client.flows
def retrieve(self, id: str, *, more_voice_version: str | Unset = UNSET) -> _m.Flow
```

`client.flows.retrieve()` · `await async_client.flows.retrieve()` · `GET /flows/{id}` · [API reference](https://docs.morevoice.ai/api/operations/flows_retrieve/)

### Parameters

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

### Returns

`Flow`:

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | The flow's ID. |
| `object` | `"flow"` | Always `flow`. |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `name` | `string` | — |
| `description` | `string` | — |
| `kind` | `"voice" \| "agent_script" \| "ivr"` | voice: drives an AI assistant; agent_script: a human agent's branching script; ivr: a phone menu. |
| `status` | `"draft" \| "published" \| "archived"` | — |
| `published_version` | `integer \| null` | The version calls run (null: never published). |
| `latest_version` | `integer` | — |
| `draft_rev` | `integer` | The draft's revision: send it as `base_rev` when you write the draft. |
| `assistant_id` | `string \| null` | `asst_…` ID. |
| `template_id` | `string \| null` | — |
| `node_count` | `integer` | — |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow = client.flows.retrieve("flow_7Hk2Lm9Qp")
print(flow)
```

## `retrieve_analytics()`

**Retrieve a flow's analytics.** How this key's mode's calls went through the flow (the latest 5000 in the range): visits, calls, drop-off, caller turns and errors per node, how often each transition was taken, how calls ended, and IVR KPIs for IVR flows. Filter by `from` / `to` (start time) and a published `version`.

```python
# client.flows
def retrieve_analytics(self, id: str, *, from_: _dt.datetime | Unset = UNSET, to: _dt.datetime | Unset = UNSET, version: str | Unset = UNSET, more_voice_version: str | Unset = UNSET) -> _m.FlowAnalytics
```

`client.flows.retrieve_analytics()` · `await async_client.flows.retrieve_analytics()` · `GET /flows/{id}/analytics` · [API reference](https://docs.morevoice.ai/api/operations/flows_retrieve_analytics/)

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `str` | yes | A flow ID (`flow_…`). |
| `from` | `string` | no | Calls that started at or after this time (ISO 8601). |
| `to` | `string` | no | Calls that started at or before this time (ISO 8601). |
| `version` | `string` | no | Only calls that ran this published version. |

### Returns

`FlowAnalytics`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_analytics"` | Always `flow_analytics`. |
| `flow_id` | `string` | A flow ID (prefix `flow_`). |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `from` | `string \| null` | — |
| `to` | `string \| null` | — |
| `version` | `integer \| null` | — |
| `calls` | `integer` | Calls that ran the flow in the range (at most the latest 5000). |
| `nodes` | `object[]` | — |
| `transitions` | `object[]` | — |
| `ends` | `object[]` | — |
| `ivr` | `object \| null` | IVR flows: containment, abandon rate, keypad vs speech, per menu. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_analytics = client.flows.retrieve_analytics("flow_7Hk2Lm9Qp")
print(flow_analytics)
```

## `retrieve_draft()`

**Retrieve a flow's draft.** The editable graph and its revision (`rev`: send it back as `base_rev`).

```python
# client.flows
def retrieve_draft(self, id: str, *, more_voice_version: str | Unset = UNSET) -> _m.FlowDraft
```

`client.flows.retrieve_draft()` · `await async_client.flows.retrieve_draft()` · `GET /flows/{id}/draft` · [API reference](https://docs.morevoice.ai/api/operations/flows_retrieve_draft/)

### Parameters

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

### Returns

`FlowDraft`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_draft"` | Always `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. |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_draft = client.flows.retrieve_draft("flow_7Hk2Lm9Qp")
print(flow_draft)
```

## `retrieve_usage()`

**Retrieve what uses a flow.** Returns the `FlowUsage` object. Answers `404` with the code `resource_missing` when nothing has this ID in this organisation and mode.

```python
# client.flows
def retrieve_usage(self, id: str, *, more_voice_version: str | Unset = UNSET) -> _m.FlowUsage
```

`client.flows.retrieve_usage()` · `await async_client.flows.retrieve_usage()` · `GET /flows/{id}/usage` · [API reference](https://docs.morevoice.ai/api/operations/flows_retrieve_usage/)

### Parameters

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

### Returns

`FlowUsage`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_usage"` | Always `flow_usage`. |
| `flow_id` | `string` | A flow ID (prefix `flow_`). |
| `assistants` | `object[]` | — |
| `copilot_profiles` | `object[]` | — |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_usage = client.flows.retrieve_usage("flow_7Hk2Lm9Qp")
print(flow_usage)
```

## `retrieve_version()`

**Retrieve a flow version.** A published version, with its graph.

```python
# client.flows
def retrieve_version(self, id: str, version: str, *, more_voice_version: str | Unset = UNSET) -> _m.FlowVersion
```

`client.flows.retrieve_version()` · `await async_client.flows.retrieve_version()` · `GET /flows/{id}/versions/{version}` · [API reference](https://docs.morevoice.ai/api/operations/flows_retrieve_version/)

### Parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | `str` | yes | A flow ID (`flow_…`). |
| `version` | `str` | yes | The version number. |

### Returns

`FlowVersion`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_version"` | Always `flow_version`. |
| `flow_id` | `string` | A flow ID (prefix `flow_`). |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `version` | `integer` | — |
| `note` | `string` | — |
| `checksum` | `string` | — |
| `node_count` | `integer` | — |
| `edge_count` | `integer` | — |
| `created` | `string` | An ISO-8601 timestamp in UTC. |
| `graph` | `FlowGraph` | A flow's graph: nodes (v1 node schema) wired by their transitions' `next`, variables and settings. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_version = client.flows.retrieve_version("flow_7Hk2Lm9Qp", "3")
print(flow_version)
```

## `simulate()`

**Simulate a call through a flow.** Runs a text-only call through the flow's draft (or a published `version`) with the real flow engine and the assistant's model, and answers what happened: the turns, the nodes entered, the actions (dry runs: no API or tool request is sent) and where the call stands. Send the caller's lines as `messages` / `message`, keys as `dtmf`, silence as `no_response`. Continue the same simulation with `sim_id` (it lives 15 minutes). With a test key the models are mocks.

Send `Accept: text/event-stream` to receive the same simulation as Server-Sent Events while it runs: `sim.started` (`sim_id`, `resumed`, `kind`), then `sim.node`, `sim.turn` and `sim.action` (each with the fields of the matching FlowSimulation entry) in order, and last `sim.done`, whose data is this endpoint's JSON answer; `error` ends a failed run. Closing the connection stops the simulation. A streamed answer counts against the key's stream limit and is not stored for Idempotency-Key replays.

```python
# client.flows
def simulate(self, id: str, body: _m.FlowSimulateParamsInput | Mapping[str, Any] | Unset = UNSET, *, more_voice_version: str | Unset = UNSET, idempotency_key: str | Unset = UNSET) -> _m.FlowSimulation
```

`client.flows.simulate()` · `await async_client.flows.simulate()` · `POST /flows/{id}/simulate` · [API reference](https://docs.morevoice.ai/api/operations/flows_simulate/)

### Parameters

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

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `dtmf` | `string` | no | Keys the caller presses, in order (after `messages`, before `message`); the entry then completes. |
| `message` | `string` | no | One more caller line (after `messages`). |
| `messages` | `string[]` | no | What the caller says, one line per turn, in order. |
| `no_response` | `boolean` | no | The caller stays silent (a no-response timeout). |
| `sim_id` | `string` | no | Continue this simulation (the `id` of an earlier answer; it lives 15 minutes after its last turn). Default: a new one. |
| `variables` | `Record<string, string \| number \| boolean \| null>` | no | Variables for the simulated call (merged over the flow's sample values). |
| `version` | `integer` | no | Simulate this published version. Default: the draft. |

### Returns

`FlowSimulation`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_simulation"` | Always `flow_simulation`. |
| `id` | `string` | The simulation's ID: send it as `sim_id` to continue. |
| `flow_id` | `string` | A flow ID (prefix `flow_`). |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `resumed` | `boolean` | This request continued an existing simulation. |
| `turns` | `object[]` | What was said during this request, in order. |
| `path` | `object[]` | The nodes entered during this request, in order. |
| `actions` | `object[]` | Actions and tool calls during this request (dry runs). |
| `ended` | `boolean` | — |
| `end_reason` | `string \| null` | — |
| `current_node_key` | `string \| null` | — |
| `variables` | `object` | The call's variables now (sensitive ones redacted). |
| `coverage` | `object` | — |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_simulation = client.flows.simulate("flow_7Hk2Lm9Qp", {
    "messages": [
        "Hi, I'd like to book an appointment",
        "Tomorrow at 10",
    ],
})
print(flow_simulation)
```

## `update()`

**Update a flow.** Changes only the fields you send. Returns the updated `Flow`. Answers `404` with the code `resource_missing` when nothing has this ID in this organisation and mode.

```python
# client.flows
def update(self, id: str, body: _m.FlowUpdateParamsInput | Mapping[str, Any] | Unset = UNSET, *, more_voice_version: str | Unset = UNSET) -> _m.Flow
```

`client.flows.update()` · `await async_client.flows.update()` · `PATCH /flows/{id}` · [API reference](https://docs.morevoice.ai/api/operations/flows_update/)

### Parameters

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

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `archived` | `boolean` | no | true archives the flow (hidden from lists); false restores it. |
| `assistant_id` | `string \| null` | no | `asst_…` ID. |
| `description` | `string` | no | — |
| `name` | `string` | no | — |

### Returns

`Flow`:

| Field | Type | Description |
| --- | --- | --- |
| `id` | `string` | The flow's ID. |
| `object` | `"flow"` | Always `flow`. |
| `livemode` | `boolean` | `true` in live mode, `false` in test mode. |
| `name` | `string` | — |
| `description` | `string` | — |
| `kind` | `"voice" \| "agent_script" \| "ivr"` | voice: drives an AI assistant; agent_script: a human agent's branching script; ivr: a phone menu. |
| `status` | `"draft" \| "published" \| "archived"` | — |
| `published_version` | `integer \| null` | The version calls run (null: never published). |
| `latest_version` | `integer` | — |
| `draft_rev` | `integer` | The draft's revision: send it as `base_rev` when you write the draft. |
| `assistant_id` | `string \| null` | `asst_…` ID. |
| `template_id` | `string \| null` | — |
| `node_count` | `integer` | — |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow = client.flows.update("flow_7Hk2Lm9Qp", {
    "name": "Reception (2026)",
})
print(flow)
```

## `update_draft()`

**Replace a flow's 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.

```python
# client.flows
def update_draft(self, id: str, body: _m.FlowDraftParamsInput | Mapping[str, Any], *, more_voice_version: str | Unset = UNSET) -> _m.FlowDraft
```

`client.flows.update_draft()` · `await async_client.flows.update_draft()` · `PUT /flows/{id}/draft` · [API reference](https://docs.morevoice.ai/api/operations/flows_update_draft/)

### Parameters

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

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `graph` | `FlowGraphParamsInput` | yes | A whole graph to write. Nodes are matched to the stored draft by `key`. |
| `base_rev` | `integer` | yes | The draft `rev` you read: a newer draft (changed elsewhere) answers 409 and nothing is written. |

### Returns

`FlowDraft`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_draft"` | Always `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. |
| `updated` | `string` | An ISO-8601 timestamp in UTC. |

### Example

```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)
```

## `validate()`

**Validate a flow graph.** Checks a graph without saving it: the errors that would block publishing, plus warnings and tasks. A malformed graph answers 400.

```python
# client.flows
def validate(self, body: _m.FlowValidateParamsInput | Mapping[str, Any], *, more_voice_version: str | Unset = UNSET, idempotency_key: str | Unset = UNSET) -> _m.FlowValidation
```

`client.flows.validate()` · `await async_client.flows.validate()` · `POST /flows/validate` · [API reference](https://docs.morevoice.ai/api/operations/flows_validate/)

### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `graph` | `FlowGraphParamsInput` | yes | A whole graph to write. Nodes are matched to the stored draft by `key`. |

### Returns

`FlowValidation`:

| Field | Type | Description |
| --- | --- | --- |
| `object` | `"flow_validation"` | Always `flow_validation`. |
| `valid` | `boolean` | No errors: it can be published. |
| `issues` | `object[]` | — |

### Example

```python
from morevoice import MoreVoice

client = MoreVoice()  # MOREVOICE_API_KEY from the environment

flow_validation = client.flows.validate({
    "graph": {
        "kind": "voice",
        "nodes": [
            {
                "key": "start",
                "transitions": [
                    {
                        "condition": {
                            "kind": "always",
                        },
                        "next": None,
                    },
                ],
                "type": "start",
            },
        ],
    },
})
print(flow_validation)
```
