> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://onepin.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://onepin.ai/docs/_mcp/server.

# Workflow

> How an Onepin workflow definition works — the graph of Source, Operator, Validator, and Sink nodes, how a line of script becomes finished audio, and how to edit a definition in code.

Every workflow is a **definition**: a graph of typed nodes connected by edges. A line of script enters at one end, passes through the nodes you wire up, and leaves as finished audio. When you clone a template you get a ready-made graph; to change what it says, who speaks, or what comes out, you edit node `config` objects.

```
definition
├── graph
│   ├── nodes[]   — id (UUID), type, name, position, config
│   └── edges[]   — id, source, sourcePort, target, targetPort
└── execution     — run-time settings
```

## The four node families

Every node belongs to one of four families. Open a node for what it does, its config, and how to inspect it live.

| Family        | What it does                                  | Nodes                                                                                                                                                                                                                                                      |
| ------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Source**    | Brings script in                              | [Script](/docs/workflow/script)                                                                                                                                                                                                                            |
| **Operator**  | Transforms lines                              | [Translator](/docs/workflow/translator) · [Normalizer](/docs/workflow/normalizer) · [Generator](/docs/workflow/generator) · [Phoneme Injector](/docs/workflow/phoneme-injector) · [Pronunciation Corrector](/docs/workflow/pronunciation-corrector)        |
| **Validator** | Scores lines and routes them `pass` or `fail` | [How validators work](/docs/workflow/validators) · [Accuracy](/docs/workflow/accuracy-validator) · [Naturalness](/docs/workflow/naturalness-validator) · [Noise](/docs/workflow/noise-validator) · [Pronunciation](/docs/workflow/pronunciation-validator) |
| **Sink**      | Sends the result out                          | [Export](/docs/workflow/export)                                                                                                                                                                                                                            |

A validator is not a kind of operator. An operator rewrites a line and hands it on; a validator leaves the line alone and decides where it goes next — which is why it alone has two output ports. The API agrees: `GET /api/v2/nodes/{node_type}` returns `category`, and it reads `source`, `operator`, `validation`, or `output`.

> **Note**
>
> In a definition's JSON, each node's `type` carries its internal id, and those are what you write when you author a definition by hand:
>
> * **Source** — `source_script` (Script)
> * **Operator** — `operator_translator` · `operator_normalizer` · `operator_generator` (Generator) · `operator_phoneme_injector` · `operator_pronunciation_corrector`
> * **Validator** — `validator_error_rate` (Accuracy) · `validator_naturalness` · `validator_noise` (Noise) · `validator_pronunciation` (Pronunciation)
> * **Sink** — `sink_preview` (Export)
>
> The prefix is the family, with one exception to watch for: Accuracy is `validator_error_rate`, not `validator_accuracy`.
>
> Run `onepin nodes list` for the live list with each node's display name and ports — that, not this page, is the source of truth for what a node is called in the app.

## How lines flow

Every edge carries **lines**. A line is one piece of script plus its language, and it picks up more as it moves through the graph:

```
Script → (translated) → (normalized) → Generator → validators → Export
 text        text            text        + audio    + scores    downloaded
```

A port only accepts a line that already carries what it needs. Export, for example, requires audio — and only the Generator adds audio — so a Generator always sits upstream of Export. Onepin checks these connections when you save; an edge that can't carry what the next node needs is rejected with a clear message. See [General rules](/docs/workflow/general-rules) for the full set.

## Editing a definition

Definitions are replaced whole, not merged — so the reliable pattern is **read → modify → write back**:

```python
definition = client.workflows.get(workflow_id=workflow_id).data.model_dump()["definition"]
for node in definition["graph"]["nodes"]:
    if node["type"] == "source_script":
        node["config"] = {"input_type": "text", "source_language": "en-us", "text": "..."}
client.workflows.patch_workflow(workflow_id, definition=definition)
```

The [Run a workflow](/docs/guides/run-a-workflow) guide walks this end to end. Authoring a definition from scratch (`client.workflows.create_workflow` / `onepin workflows create --definition @file.json`) follows the same schema — start from `onepin workflows definition-schema`.

## Estimating cost before running

```bash
onepin workflows preview-run <WORKFLOW_ID>     # estimate a run without executing it
```

Also available per template (`GET /api/v1/templates/{id}/estimate`) and via the SDK (`client.workflows.preview_run`, `client.workflows.estimate_workflow`).

## Related

* [General rules](/docs/workflow/general-rules) — what makes a graph valid
* [Run a workflow](/docs/guides/run-a-workflow) — edit a definition entirely in code
* [Voices & Models](/docs/get-started/voices-models) — the model catalog
* [API Reference](/docs/api-reference) — the REST surface, endpoint by endpoint