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

# Node Reference

> Detailed reference for every node type available in Datazone Flows

## Common Properties

Every node in a flow document shares the same envelope:

| Property | Type   | Description                                                                                                     |
| -------- | ------ | --------------------------------------------------------------------------------------------------------------- |
| `id`     | string | Unique identifier for the node within the flow                                                                  |
| `type`   | string | Node type: `start`, `if`, `for_each`, `llm_call`, `rest_call`, `action_call`, `python`, `response`, or `output` |
| `label`  | string | (Optional) Display name shown on the canvas                                                                     |
| `config` | object | Type-specific configuration, validated against that node type's schema                                          |

<Note>
  Each node type also declares a fixed set of **input** and **output** ports (e.g. `in` / `out`). [Connections](/reference/flows/yaml-reference#connections) wire an upstream node's output port to a downstream node's input port.
</Note>

## Start

The entry point of a flow. It takes no configuration and no inputs — it simply emits the run's parameters and a trigger timestamp so downstream nodes have a well-defined starting payload.

| Property | Category | Inputs | Outputs |
| -------- | -------- | ------ | ------- |
| `start`  | trigger  | —      | `out`   |

```yaml theme={null}
- id: trigger
  type: start
  label: Start
  config: {}
```

**Output:**

```json theme={null}
{
  "kind": "start",
  "parameters": { "...": "the run's parameters" },
  "triggered_at": "2026-07-24T12:00:00+00:00"
}
```

<Note>
  Every flow must have exactly one `start` node as its entry point.
</Note>

## If

Branches the flow based on a condition evaluated against upstream data and flow parameters.

| Property | Category                | Inputs | Outputs         |
| -------- | ----------------------- | ------ | --------------- |
| `if`     | control (**branching**) | `in`   | `true`, `false` |

| Attribute  | Type   | Default | Description                                                                                                 |
| ---------- | ------ | ------- | ----------------------------------------------------------------------------------------------------------- |
| `left`     | string | —       | Python expression evaluated with `inputs`/`parameters` in scope (required)                                  |
| `operator` | string | `eq`    | One of `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `contains`, `is_true`, `is_false`, `is_empty`, `is_not_empty` |
| `right`    | any    | `null`  | Right-hand operand. Ignored for `is_true`/`is_false`/`is_empty`/`is_not_empty`                              |

```yaml theme={null}
- id: check_status
  type: if
  label: Is approved?
  config:
    left: "inputs['in']['status']"
    operator: eq
    right: "approved"
```

Because `if` is a **branching** node, every outgoing connection from it must set `from_port` to `true` or `false`:

```yaml theme={null}
connections:
  - from: check_status
    to: send_email
    from_port: "true"
  - from: check_status
    to: log_rejection
    from_port: "false"
```

<Warning>
  A connection leaving a branching node without a valid `from_port` fails validation. Nodes only reachable through the branch that isn't chosen at run time are marked `SKIPPED` instead of executed.
</Warning>

When the upstream input is a dict, its fields are merged into the output alongside `branch` and `value`, so downstream nodes on either branch still see the original payload.

## For Each

Iterates over a list, re-running a nested **body** sub-flow once per item.

| Property   | Category                | Inputs | Outputs |
| ---------- | ----------------------- | ------ | ------- |
| `for_each` | control (**container**) | `in`   | `out`   |

| Attribute        | Type   | Default   | Description                                                                                                  |
| ---------------- | ------ | --------- | ------------------------------------------------------------------------------------------------------------ |
| `items`          | string | —         | Python expression evaluated with `inputs`/`parameters` in scope; must evaluate to a list/iterable (required) |
| `item_as`        | string | `item`    | Parameter name the current item is exposed under inside the body, as `parameters[item_as]`                   |
| `index_as`       | string | `index`   | Parameter name the current index is exposed under inside the body (omit to disable)                          |
| `max_iterations` | int    | `1000`    | Safety cap — exceeding it raises a run error                                                                 |
| `save_as`        | string | `results` | Output key the collected per-iteration results are stored under                                              |
| `body`           | object | —         | A full nested flow document (its own `nodes`/`connections`), required                                        |

```yaml theme={null}
- id: process_orders
  type: for_each
  label: Process each order
  config:
    items: "inputs['in']['orders']"
    item_as: order
    index_as: index
    max_iterations: 500
    save_as: results
    body:
      flow:
        name: process_orders_body
      nodes:
        - id: body_start
          type: start
          config: {}
        - id: format_order
          type: python
          config:
            code: |
              def handler(inputs, parameters):
                  order = parameters["order"]
                  return {"id": order["id"], "total": order["amount"] * 1.1}
        - id: body_response
          type: response
          config: {}
      connections:
        - from: body_start
          to: format_order
        - from: format_order
          to: body_response
```

<Note>
  The `body` document is validated the exact same way a top-level flow is, including supporting another `for_each` nested inside it (up to a max depth of 5). It **must contain exactly one `response` node** — that node's output is what gets collected into `save_as` for each iteration.
</Note>

## LLM Call

Calls a Large Language Model through a configured [Model Account](/reference/development/model-accounts), or the organization's Orion AI default account when omitted.

| Property   | Category               | Inputs | Outputs |
| ---------- | ---------------------- | ------ | ------- |
| `llm_call` | ai (needs credentials) | `in`   | `out`   |

| Attribute          | Type   | Default    | Description                                                                            |
| ------------------ | ------ | ---------- | -------------------------------------------------------------------------------------- |
| `model_account_id` | string | `null`     | Model account to use. Omit to use the organization's Orion AI settings                 |
| `model`            | string | `null`     | Model enum value (e.g. `GPT_4O`). Omit to use the organization default                 |
| `prompt`           | string | —          | Prompt template, required. Supports `{inputs[...]}` / `{parameters[...]}` substitution |
| `system_prompt`    | string | `null`     | (Optional) System prompt, same templating support                                      |
| `save_as`          | string | `response` | Output key the model's response text is stored under                                   |
| `timeout_sec`      | int    | `60`       | Request timeout in seconds                                                             |

```yaml theme={null}
- id: summarize
  type: llm_call
  label: Summarize ticket
  config:
    model_account_id: "664f1c2e5a2ac9f0d39326"
    model: GPT_4O
    system_prompt: "You are a support triage assistant."
    prompt: "Summarize this ticket in one sentence: {inputs[in][body]}"
    save_as: summary
    timeout_sec: 45
```

<Note>
  `prompt`/`system_prompt` use Python's `str.format()` templating (not Jinja) — see [Templating & Expressions](/reference/flows/templating#llm_call-and-action_call-templating) for the exact rules and error behavior when a referenced field is missing.
</Note>

## REST Call

Calls an external HTTP/REST endpoint.

| Property    | Category    | Inputs | Outputs    |
| ----------- | ----------- | ------ | ---------- |
| `rest_call` | integration | `in`   | `response` |

| Attribute                        | Type   | Default    | Description                                                                                                                      |
| -------------------------------- | ------ | ---------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `url`                            | string | —          | Target URL, required. Must start with `http://` or `https://`                                                                    |
| `method`                         | string | `GET`      | One of `GET`, `POST`, `PUT`, `PATCH`, `DELETE`                                                                                   |
| `headers`                        | object | `{}`       | Request headers                                                                                                                  |
| `query`                          | object | `{}`       | Query parameters. Values that reference `inputs`/`parameters` are evaluated as Python expressions; plain literals are sent as-is |
| `json_body`                      | object | `null`     | JSON request body                                                                                                                |
| `timeout_sec`                    | int    | `30`       | Request timeout in seconds                                                                                                       |
| `save_as`                        | string | `response` | Output key the parsed response body is stored under                                                                              |
| `auth_type`                      | string | `none`     | One of `none`, `basic`, `bearer`, `api_key`                                                                                      |
| `username` / `password`          | string | `null`     | Used when `auth_type: basic`                                                                                                     |
| `token`                          | string | `null`     | Used when `auth_type: bearer` — sent as `Authorization: Bearer <token>`                                                          |
| `api_key_name` / `api_key_value` | string | `null`     | Used when `auth_type: api_key` — sent as a `<api_key_name>: <api_key_value>` header                                              |

```yaml theme={null}
- id: fetch_weather
  type: rest_call
  label: Fetch London weather
  config:
    url: "https://api.open-meteo.com/v1/forecast"
    method: GET
    query:
      latitude: "51.5074"
      longitude: "-0.1278"
      current_weather: "true"
    timeout_sec: 30
    save_as: weather
```

Authenticated example:

```yaml theme={null}
- id: call_billing_api
  type: rest_call
  label: Get invoice
  config:
    url: "https://billing.example.com/api/invoices/{parameters[invoice_id]}"
    method: GET
    auth_type: bearer
    token: "sk_live_..."
    save_as: invoice
```

The response is always returned alongside its `status_code`:

```json theme={null}
{ "response": { "...": "parsed JSON or raw text" }, "status_code": 200 }
```

## Action Call

Calls a project [Action](/reference/development/actions) — a user-defined Python function — with parameters.

| Property      | Category                        | Inputs | Outputs |
| ------------- | ------------------------------- | ------ | ------- |
| `action_call` | integration (needs credentials) | `in`   | `out`   |

| Attribute     | Type   | Default  | Description                                                                                           |
| ------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------- |
| `action_id`   | string | —        | Id of the Action to call, required                                                                    |
| `parameters`  | object | `{}`     | Parameters passed to the action. String values support `{inputs[...]}`/`{parameters[...]}` templating |
| `save_as`     | string | `result` | Output key the action's return value is stored under                                                  |
| `timeout_sec` | int    | `30`     | Timeout in seconds                                                                                    |

```yaml theme={null}
- id: send_welcome_email
  type: action_call
  label: Send welcome email
  config:
    action_id: "664f1c2e5a2ac9f0d39326"
    parameters:
      to: "{inputs[in][email]}"
      name: "{inputs[in][full_name]}"
    save_as: email_result
    timeout_sec: 30
```

<Note>
  Actions are audited the same way as when an agent calls them — every `action_call` node execution appears in the Action's call history.
</Note>

## Python

Runs custom Python against upstream data and flow parameters, in an isolated subprocess.

| Property | Category  | Inputs | Outputs |
| -------- | --------- | ------ | ------- |
| `python` | transform | `in`   | `out`   |

| Attribute | Type   | Description                                                                           |
| --------- | ------ | ------------------------------------------------------------------------------------- |
| `code`    | string | A complete Python module defining a `handler(inputs, parameters)` function (required) |

```yaml theme={null}
- id: convert_temperature
  type: python
  label: Convert temperature
  config:
    code: |
      def handler(inputs, parameters):
          # inputs     – dict of upstream node outputs, keyed by port name
          # parameters – dict of flow run parameters
          weather = inputs.get("in", {}).get("weather", {})
          celsius = weather.get("current_weather", {}).get("temperature")
          fahrenheit = round(celsius * 9 / 5 + 32, 1)
          return {"celsius": celsius, "fahrenheit": fahrenheit}
```

<Warning>
  `code` must define a `handler(inputs, parameters)` function and be valid Python — both are checked before the flow can run.
</Warning>

## Response

A terminal node that returns the upstream result, unchanged, to the flow's caller.

| Property   | Category | Inputs          | Outputs |
| ---------- | -------- | --------------- | ------- |
| `response` | terminal | `in` (required) | —       |

```yaml theme={null}
- id: finish
  type: response
  label: Response
  config: {}
```

<Note>
  A flow may contain **at most one** top-level `response` node. Inside a `for_each` body, exactly **one** `response` node is required — it defines that iteration's result.
</Note>

## Output

A sink node — writes the upstream result to a dataset, webhook, or file.

| Property | Category | Inputs          | Outputs |
| -------- | -------- | --------------- | ------- |
| `output` | sink     | `in` (required) | —       |

| Attribute       | Type   | Default | Description                                                               |
| --------------- | ------ | ------- | ------------------------------------------------------------------------- |
| `kind`          | string | —       | One of `dataset`, `webhook`, `file` (required)                            |
| `dataset_alias` | string | `null`  | Required when `kind: dataset`                                             |
| `materialized`  | bool   | `false` | Reserved for a future materialized dataset write path — not yet supported |
| `url`           | string | `null`  | Required when `kind: webhook`. Must start with `http://` or `https://`    |
| `path`          | string | `null`  | Required when `kind: file`                                                |

```yaml theme={null}
- id: post_result
  type: output
  label: Send to webhook
  config:
    kind: webhook
    url: "https://hooks.example.com/flow-result"
```

```yaml theme={null}
- id: write_dataset
  type: output
  label: Write to dataset
  config:
    kind: dataset
    dataset_alias: "processed_orders"
```

<Warning>
  Setting `materialized: true` on a `kind: dataset` output currently fails validation — materialized dataset writes are not supported yet.
</Warning>

## Next Steps

* [Overview](/reference/flows/overview) - flow structure and core concepts
* [Templating & Expressions](/reference/flows/templating) - exactly how each node type consumes `inputs`/`parameters`
* [YAML Reference](/reference/flows/yaml-reference) - the complete flow document schema
