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

# Workflow editor

> Build visual processing workflows with the drag-and-drop editor.

The workflow editor is a visual canvas where you design your workflow by adding nodes and connecting them with edges.

## Opening and leaving the editor

The editor is a page of its own at `/workflows/<workflow id>/builder`, reached from the **Builder** action on the workflow detail page. Because it has a real address you can bookmark it, share it, and open it in a new tab.

A section this workflow calls opens in a window over the editor rather than replacing it, so you can work on the section and come straight back without losing your place. See [Call Workflow](/nodes/call-workflow).

It takes the whole window: the app's navigation is set aside so the canvas, the node rail and the properties panel get the full width. Use the back arrow beside the workflow name to return to the workflow, or your browser's Back button.

<Warning>Leaving with unsaved edits discards them. Ingestly asks first - on the back arrow, on the browser's Back button, and on a page reload - and you can either **Keep editing** or **Discard**. Save before you leave to keep the draft.</Warning>

## Node rail

The **node rail** is a compact icon strip on the left edge of the editor. It groups nodes into three categories:

* **Triggers**
* **Actions**
* **Outputs**

Hover any category icon to expand the rail into a floating palette listing every node in that category, along with a **Search nodes** field that filters by name or description. The palette stays open while your cursor is over it and collapses when you move away.

Within each category (**Triggers**, **Actions**, **Outputs**), nodes are listed alphabetically by name. The edge-drag node picker (shown when you drag an edge to empty canvas) is likewise sorted alphabetically.

To add a node, drag a card from the expanded palette onto the canvas. A highlighted ring appears on the canvas while you drag to confirm the drop target.

<Tip>When the canvas is empty, an inline hint reads "Drag a trigger from the left to begin." Start there, then connect actions and outputs as you build out the workflow.</Tip>

See [node types](/nodes/introduction) for a complete reference of all available nodes.

## Connecting nodes

Click the output handle of one node and drag to the input handle of another node to create an edge. Edges define the flow of data through your workflow.

Rules for connections:

* Data flows from left to right (trigger → action → output)
* You cannot create circular connections
* Some node types support multiple input or output connections
* Edges between incompatible node types are prevented

When you connect two nodes, Ingestly creates the edge with the default **On success** condition. To change it, click the edge and edit the **Condition** in the properties panel. See [conditional routing](/guides/conditional-routing) for the full set of edge condition types and operators.

### Branch from a node

To author multiple outgoing branches in one shot, click the **branch** action in a node's hover toolbar. The **Add branches** modal lets you list several rules and optionally add an **Otherwise** edge. Ingestly creates one outgoing edge per rule, each wired to a placeholder target that you can replace with a real node.

## Properties panel

Click a node or edge to open the **properties panel** on the right side of the editor. The panel stays open as you click between nodes so you can step through the graph without reopening it. Click outside the panel or use the close button to dismiss it.

When you select a node, Ingestly pans it to the center of the visible canvas and zooms in to a focus level so it reads clearly even with the side panels open. This accounts for the space taken by the properties panel and data picker. Deselecting restores the previous position and zoom.

Field help is shown via a help icon next to each field's label. Click it to open a popover describing the field and its options, instead of always-visible description text. Toggle fields render inline with their label.

**Resize** the panel by dragging its left edge. The panel width is constrained between a minimum and maximum so your canvas stays usable.

## Template fields

Fields that accept `{{ ... }}` references (URLs, headers, email subjects, transform outputs, and the other fields described in [expressions](/guides/expressions)) show each reference as an inline pill instead of raw text. A pill carries the upstream node's icon, the field path, and a type chip. It turns red when the reference does not resolve and amber when the node it points at is not guaranteed to run before this one.

* **Suggestions:** type `{{` or press Ctrl+Space to open a dropdown grouped by upstream node. Each row shows the field type and, when a document is selected in the toolbar, a sample value from its latest run. Keep typing to search every nested path at once. Press Enter or Tab to drill into a node or accept a field, and Escape to dismiss.
* **Insert reference button:** click the `{}` button beside a field to browse without typing. The **Data** tab lists upstream fields as a searchable tree, **Functions** lists the built-in helpers, and **Filters** lists the filters that fit the selected pill.
* **Editing a pill:** hover a pill to see its card with the resolved type, source node, and sample value. Click the pill to select it and reveal **Edit**, **Add filter**, **Go to node**, and **Remove**. Press Enter or double-click to edit the reference as text; it becomes a pill again when you type the closing `}}` or leave the field. Backspace and Delete remove a pill whole.
* **Preview:** when a referenced node has a run sample, a muted line under the field shows what the value resolves to. Multiline fields keep the preview behind a toggle.

The [Data picker](#data-picker) still inserts a token into the focused field when you click or drag one of its rows.

## Data picker

When you select a node, a **Data picker** column opens beside the properties panel and lists every upstream node's output as a tree of fields. The picker helps you discover what is available to reference without leaving the editor.

* **Browse:** expand any upstream node to see its `payload`, `metadata`, and nested fields. Object and array fields nest inline with proper indentation, so `items[].amount` appears under `items` rather than as a flat key.
* **Insert a token:** click any field to insert its template token (`{{nodeName.payload.field}}`) into the focused template editor, or drag the field onto the editor.
* **Sample values:** select a document from the toolbar to see real values from that document's latest run beside each field. Without a document, the picker shows the field schema only.
* **Loop iteration:** when the selected node sits inside a [Loop](/nodes/loop) body, the picker exposes the per-item iteration token alongside the loop source array so you can reference `item.path` instead of the full collection.

Drag the picker's left edge to resize it. Click the hide button in the picker header to collapse it to a single show-button column and reclaim canvas width; click the show button to bring the picker back.

## Code editors

Some node configurations include code editors, such as the [validation node](/nodes/validation) script mode and JSON Schema fields. The editors are powered by Monaco and provide:

* **Syntax highlighting** for JavaScript and JSON
* **Autocomplete suggestions** including template variable autocomplete. Type `{{` to see available variables from upstream nodes
* **Inline error reporting** with underlined errors and hover details
* **JSON validation** for schema fields, showing errors when the JSON structure is invalid

### Editor toolbar

Above each code editor, a toolbar provides formatting buttons for common operations like indenting, commenting, and wrapping selections.

### Fullscreen editing

Click the **expand** button in the top-right corner of any code editor to open it in fullscreen mode. This gives you a larger workspace for complex scripts or schemas. Press **Escape** or click the collapse button to return to the inline view.

## Canvas toolbar

The toolbar sits above the canvas at full width and contains the primary editing controls:

* **Environment badge**: shows the workflow's [environment](/workflows/stages), a neutral badge for **Development** and an amber badge for **Production**
* **Save** (`Ctrl+S`): save the current workflow. An amber indicator appears if the workflow saved but has validation errors
* **Activate** / **Active**: activate or deactivate the workflow directly from the editor
* **Undo** (`Ctrl+Z`) and **Redo** (`Ctrl+Shift+Z`): step through edit history for your current session
* **Auto layout** (`Ctrl+L`, or double-click an empty spot on the canvas): reorganize nodes into a clean left-to-right layout. After arranging the nodes, it rescales the view to fit the whole workflow in the canvas, rather than keeping your prior zoom
* **More canvas actions** menu: **Revert to saved**, **Revert to last valid** (when the current save is invalid), and **Use template** to populate the canvas from a saved template
* **More actions** menu in the header: **Workflow versions** to open the version history drawer (see below), **Workflow settings** (see below), **Enable self-learning** to turn [self-learning](/workflows/self-learning) on and open its **Learning** tab (organizations with self-learning, while it is off), **Save as Template**, **Export to file**, **Import from file**, **Copy to Production** or **Copy to Development** to copy the saved graph to the other [environment](/workflows/stages), and **Validate workflow**

## Editing shortcuts and node controls

The editor supports keyboard shortcuts and a right-click context menu for fast editing. Shortcuts are suppressed while your cursor is inside a text or code field.

* **Copy** (`Ctrl+C`), **Cut** (`Ctrl+X`), and **Paste** (`Ctrl+V`): copy, cut, and paste the selected nodes and their edges, including across workflows.
* **Delete** or **Backspace**: delete the current selection. Select several nodes first to delete them together.
* **Escape**: clear the selection.
* **Save** (`Ctrl+S`), **Undo** (`Ctrl+Z`), **Redo** (`Ctrl+Y` or `Ctrl+Shift+Z`), **Revert to saved** (`Ctrl+R`), and **Auto layout** (`Ctrl+L`).

Right-click a node for **Copy**, **Duplicate**, **Copy reference**, **Disable / enable**, **Rename**, and **Delete**. Right-click empty canvas for **Paste** and **Fit view**, and right-click an edge to **Delete edge**.

Open the app command palette with `Ctrl+K` to run editor commands such as **Save workflow**, **Validate workflow**, **Auto layout**, **Fit view**, **Workflow versions**, and add-node commands by name.

### Pin a mock output

Each non-trigger node's hover toolbar has a **Pin output** action. It opens a dialog where you author a fixed JSON payload for the node to return, so you can build and test downstream nodes without running that node for real. Once a value is pinned, the action becomes **Edit pinned output**, and an **Unpin** action clears it.

## Minimap

A **minimap** in the corner of the canvas gives an overview of the whole graph and lets you pan and zoom quickly. Use the minimap control to **show** or **hide** it.

A small **Unsaved changes** badge appears in the top-left of the canvas whenever you have pending edits. Hover it to see a list of the added, modified, and removed nodes and edges.

## Workflow versions

Ingestly snapshots the workflow on every save. Click the **history** icon in the toolbar to open the
**Workflow versions** drawer, where you can browse the full history, compare any two versions, and restore
an earlier one. See [Versions](/workflows/versions) for the full picture, including checkpoints, restores,
retention, and which version a run used.

<Note>While a run started from the version currently open is still running, the editor shows a small **Run in progress on v{n}** indicator. Saving is safe: it creates a new version, and the running run keeps executing the version it started on. See [the resume rule](/workflows/versions#the-resume-rule).</Note>

## Workflow insights

**Workflow insights** in the **More actions** menu opens a page showing runs, failure rate, duration
percentiles, credits per run and per node, failure hotspots and review turnaround for this workflow.
See [Insights](/workflows/insights).

## Export and import

To move a workflow between workspaces or share it with another Ingestly account:

* **Export to file** in the **More actions** menu downloads the current workflow (nodes, edges, and node configuration) as a JSON file.
* **Import from file** lets you pick a previously exported JSON file. The contents replace the current draft, so save first or accept the confirmation dialog when you have unsaved changes.

Connectors, stores, and forward targets are exported by name, not by ID. On import, Ingestly rebinds each reference to the resource with the same name in the destination workspace. Anything that does not match is cleared, and the workflow imports with a warning listing the **unbound** connectors, stores, and forward targets together, so you can open the affected nodes and reconfigure them.

## Saving and validating

* Click **Save** to save your current workflow configuration
* The editor validates your workflow automatically and shows errors if the configuration is invalid
* Common validation errors: missing trigger, disconnected nodes, missing required configuration

## Workflow settings

Open **Workflow settings** from the **More actions** menu to edit the workflow's description, retention, reference strictness, and group without leaving the canvas. Rename the workflow from its title in the header instead.

### Strict references

**Strict references** decides what an unresolved reference costs at run time: with it on, the step fails and names the token; with it off, the reference renders as an empty string and the run carries on. New workflows are strict by default. See [strict references](/guides/expressions#strict-references) for the full behavior.

### Readiness panel

Under the switch, a readiness panel scans this workflow's recent runs so the decision is not a guess. It reports how many runs rendered a reference empty in the window and lists each offending token with its node, how many times it missed, and when it was last seen.

* **No unresolved references in the window**: turning strict on is safe.
* **One or more listed**: turning strict on would fail every one of them. Fix the paths, or add a `default` filter to the ones that are genuinely optional, before flipping the switch.

The panel follows the switch rather than the saved value, so it tells you what happens if you save what you are looking at.

## Testing runs

Use the run controls in the toolbar to test your workflow with a document from the current workflow.

* The document picker only shows documents from the current workflow
* You can test with documents in `Uploaded`, `Completed`, or `Failed` status
* The run button's dropdown lets you pick **Dry run** or **Live run** for the run

### Test step

To test a single node without re-executing the whole workflow, hover any node and click the **Test step** action in its floating toolbar, or click **Test step** in the properties panel header for the selected node. Ingestly creates a partial run that records its result on a new run row tagged as a partial run, so the original full run is never modified.

How the inputs are produced depends on whether the node has run before:

* **Already run** (warm): Ingestly re-runs just that node, reading predecessor outputs from the most recent run for the selected document so the node receives the same inputs it saw before. Descendants stay frozen and do not run.
* **Never run** (cold, first try): Ingestly runs the workflow from the trigger up to and including the selected node against the **test document** chosen in the run controls, then stops. Everything downstream of the node is skipped, so no downstream side effects fire. This lets you test a brand-new node, such as a freshly added Extract, before the workflow has ever run end to end.

The cold first-try test needs a test document selected in the document picker, and it works even on a draft or paused (disabled) workflow. If the workflow has unsaved changes when you click **Test step**, Ingestly prompts you to save first so the partial run reflects what is on screen. The button shows a spinner while the run is dispatching.

A test run charges credits for the steps it actually executes, billed at each step's real per-page cost. Steps whose inputs and configuration are unchanged are served from cache and cost nothing, so re-testing a node after tweaking a downstream schema, prompt, or template only pays for the work that actually re-ran.

To stop a cold **Test step** run partway through so you can inspect a node before it executes, set a [breakpoint](#breakpoints) on it.

### Dry run

Use a **Dry run** when you want to inspect output deliveries without sending callback requests or emails.

* Callback nodes, and Business Central and QuickBooks nodes in their Insert or Update operation, show a request preview instead of sending the request
* A Business Central or QuickBooks node in its Look up operation is a read, so it runs for real and returns the real record
* Email output nodes show an email preview instead of sending the email
* [HTTP action](/nodes/http-action) nodes preview a write (POST, PUT, PATCH, DELETE) but send a **GET** for real, so nodes downstream of a GET can still be tested
* The run output clearly shows that the result is a dry run preview

<Note>A dry run only withholds what would write outside Ingestly. Everything else - extraction, parsing, transformation, validation, routing - runs exactly as it would live.</Note>

### Live run

Use a **Live run** when you want output nodes to send real requests and emails.

<Warning>On a **Live run**, callback and email output nodes send real external outputs during the run.</Warning>

If you start a **Live run**, Ingestly asks you to confirm before it begins. The default mode follows the workflow [environment](/workflows/stages), and your choice is per run, not saved on the workflow. See [dry runs](/guides/test-mode) for the full picker.

## Breakpoints

A breakpoint pauses a run right before a specific node executes, so you can inspect its input, tweak the workflow, and continue when you are ready. There is no separate switch for this: a workflow is in debug mode exactly when it has at least one breakpoint. Setting the first breakpoint on a workflow puts it into debug mode; removing the last one takes it back out.

While a workflow is in debug mode, every run pauses at its breakpoints: a live run from an upload, email, webhook, or poller trigger, a cold **Test step** run, **Run from here**, and a manual [**Dry run** or **Live run**](#dry-run) started from the run controls' **Run** button, because all of them share the same run kind.

A workflow in debug mode shows a **Debug** badge on its detail page header and in the workflows table.

### Set and remove breakpoints

Set a breakpoint on a node with any of the following:

* Right-click the node and choose **Set breakpoint**
* Click **Set breakpoint** in the node's floating toolbar
* Select the node and press **F9**

The same three actions remove a breakpoint (**Remove breakpoint**) once one is set. A node with a breakpoint shows a red breakpoint icon in its header, the same icon as the toolbar action; hover it for the reminder that the step runs fresh.

To stop pausing without removing breakpoints one at a time, click **Clear breakpoints** in the run controls. It removes every breakpoint on the workflow in one action, which also takes the workflow out of debug mode.

<Note>
  Breakpoints belong to the workflow, not to your editor session. They are visible to everyone
  with access to the workflow, and setting, removing, or clearing them requires the
  `Core.Workflow.Update` permission (see [roles and permissions](/admin/roles-and-permissions)).
  Setting, removing, or clearing a breakpoint never marks the workflow as changed and never
  creates a new version.
</Note>

<Note>
  Breakpoints cannot be set on a **Production** workflow: the breakpoint toggle is disabled with
  the tooltip "Not available in production." [Copying a workflow to Production](/workflows/stages)
  or [duplicating](/workflows/managing#duplicating-a-workflow) one never carries its breakpoints
  to the target workflow.
</Note>

A called section pauses on its own breakpoints, independent of the workflow that calls it. Setting breakpoints on a calling workflow does not set them on the sections it calls, and the reverse is also true. Set a section's breakpoints either in the section's own workflow or in the nested view opened from its Call Workflow node; both write to the section. The nested view cannot start the section on its own (a run always starts on a document, and the document's workflow is the caller), so its toolbar offers **Dry run caller** / **Live run caller** instead: this starts the calling workflow on the inherited document, and the section runs, and pauses on its breakpoints, when the call is reached.

### Pause, inspect, continue

When a run reaches a node with a breakpoint, it pauses before that node executes:

* The node shows an amber ring and a pause indicator
* The canvas timer badge reads **Paused at breakpoint**
* A [debugger toolbar](#debugger-toolbar) appears at the top center of the canvas
* For a breakpoint park, the node's execution dialog also opens automatically, with its title suffixed **Paused at breakpoint**. A step park (see [Debugger toolbar](#debugger-toolbar)) does not open the dialog, since stepping through every node would make it pop constantly

Other branches that do not depend on the paused node may keep running while it is paused.

The inspector opens by itself when a breakpoint pauses the run (not on a step pause). If you close it, reopen it from the paused node's **Inspect** hover action; the debugger toolbar on the canvas stays available either way.

A live run pauses the same way, but there is no builder open to catch it. Its [run detail page](/runs/monitoring) shows a **Paused at breakpoint** badge and offers **Continue** next to **Cancel Run**, so you can resume on the pinned version or stop it from there. **Restart here on latest** joins them only when the workflow has been saved since the run started, and only on a top-level run; it cancels the paused run and starts a new one from the paused node on the latest saved version.

A park inside a called section is continued from that sub-run's own run detail page, reached via the **Open sub-run #N** link on the parent run's step timeline, not from the parent run's page. **Restart here on latest** is not offered there: the parent run still holds the document, so only **Continue** and **Cancel Run** apply to a section's park.

In the execution dialog:

* **Input:** the exact input the node will receive
* **Output:** the pause details, including when the node parked, an **Expires in** countdown, and a note that other branches may still be running
* **Configuration:** stays editable, so you can adjust the node while paused

The dialog footer offers two actions:

* **Continue:** runs the node against the saved workflow configuration. It is disabled with the tooltip "Save your changes first" while the workflow has unsaved changes; the pause details in the Output pane note that Continue uses the workflow as last saved.
* **Abort run:** asks "Abort run?" with "The test run is cancelled. Breakpoints stay set." Confirming cancels the run immediately

Because **Continue** always runs the saved configuration, editing the node, saving, then clicking **Continue** is how you try a change mid-run. A node with a breakpoint always executes fresh: it never reuses a cached output from an earlier run, so an AI node re-bills its credits every time it continues past a breakpoint.

<Warning>
  A paused test run still fails after 2 hours without a continue: the paused step fails with
  "Paused at breakpoint for more than 120 minutes without continue," and the run finishes as
  failed. A paused live run instead continues automatically after 2 hours, the same as if you had
  clicked **Continue**. Breakpoints stay set after an expiry, an automatic continue, an **Abort
  run**, or a **Cancel Run**.
</Warning>

While a run is paused at a breakpoint, its credit hold is released and reopened when you continue, the same as a run waiting on a [review task](/reviews/introduction).

### Debugger toolbar

While a run is paused, a debugger toolbar floats at the top center of the canvas. It replaces the **Paused at** pill that used to sit in the run controls toolbar; **Clear breakpoints** stays there. The toolbar shows **Paused at {node}**, a countdown to the 2-hour cap, and six verbs:

* **Continue** (**F5**): runs the paused node against the saved configuration and lets the run continue freely, clearing stepping for the whole run
* **Step over** (**F10**): runs the paused node, then pauses again before every node the run reaches next, on every branch. Stepping over a Call Workflow node runs the whole section (the section's own breakpoints still pause it) and pauses again at the node after the call
* **Step into** (**F11**): runs the paused node like **Step over**, but if the next node the run enters is a Call Workflow node, the run pauses inside that section at its first node instead of running the section through, and the section's builder opens over the caller. If the run reaches no Call Workflow node next, **Step into** behaves exactly like **Step over**. It is offered only when the paused node connects directly to a Call Workflow node. Once you are inside the section, **Continue** there lets the caller run on after the section returns; only **Step out** pauses the caller again
* **Step out** (**Shift+F11**): only enabled while you are inside a section opened from its Call Workflow node. Runs the rest of the section (its own breakpoints still pause it), pauses the caller at the node after the Call Workflow node, and closes the section view
* **Restart here on latest**: shown only when the workflow has been saved since the run started. Cancels the paused run and starts a new one pinned to the [latest saved version](/workflows/versions#the-resume-rule), picking up from the paused node, instead of continuing the current run on the version it started on
* **Abort run**: the same confirmation as the execution dialog's **Abort run**

When more than one node is paused at once, for example on two parallel branches, the toolbar targets the selected paused node and shows a **1 of N** switcher to move between them. **Continue** on any one of them clears stepping for the whole run, not just for that node.

The 2-hour cap that auto-continues a paused live run (see the warning above) also clears stepping, so a forgotten step never chains into a run of two-hour pauses.

**Continue**, **Step over**, **Step into**, and **Step out** are disabled with the tooltip "Save your changes first" while the workflow has unsaved changes, the same rule as the execution dialog's **Continue** button. **Abort run** is never gated on unsaved changes.

### Limits

* You cannot set a breakpoint on a node inside a [Loop](/nodes/loop) body or on a Call Workflow node itself, and a Call Workflow node itself never pauses
* Breakpoints inside a called section work: open the section from its Call Workflow node and set the breakpoint there. The section only pauses when it has its own breakpoints set. It parks in its own window, where the [debugger toolbar](#debugger-toolbar) appears with **Step out** enabled to return control to the caller (or, for a live run, its own run detail page, where you use **Continue** or **Cancel Run**). Aborting or cancelling the section also cancels the calling run
* A breakpoint on a node downstream of a Split or Classify pauses whichever branch reaches it. Each branch runs as its own child run, so several branches can be paused at the same node at once; the toolbar's **1 of N** switcher moves between them
* Breakpoints never pause the warm single-step re-test: it replays a single node against frozen inputs instead of walking the graph, so there is nothing for a breakpoint to catch
* Stepping does not reach inside a Loop body or into a Split or Classify branch's child runs, and you cannot edit a node's input at the pause

## Activating

After saving a valid workflow, click **Activate** to start accepting documents. You can also activate from the workflow's settings tab.

## Undo and redo

Use **Ctrl+Z** to undo and **Ctrl+Shift+Z** to redo changes in the editor. The undo history is maintained within your current editing session.
