> ## 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.

# Reconcile

> Compare two data sources and flag value mismatches before delivery.

<Note>This node is in **preview**. Its behavior may change in future releases.</Note>

The reconcile node compares two upstream sources (Source A and Source B) value by value and records the differences, so you can catch where an extracted document disagrees with an external system (or a second extraction) before the data is delivered.

## When to use reconcile

* Compare extracted invoice or PO data against an external system of record, fetched via a [connector](/admin/connectors) or [HTTP action](/nodes/http-action).
* Cross-check two extractions of the same document against each other.
* Gate runs to pause for review only when the two sources disagree out of tolerance. Pair this node with a downstream [Review](/nodes/review) node.

<Note>Reconcile needs **two** upstream sources connected to it. Connect both records you want to compare before configuring the node.</Note>

## Configuration

| Field                  | Type        | Required | Description                                                                                  |
| ---------------------- | ----------- | -------- | -------------------------------------------------------------------------------------------- |
| **Source A**           | select      | Yes      | One of the two records being compared, chosen from the upstream nodes connected to this node |
| **Source B**           | select      | Yes      | The other record being compared, chosen from the upstream nodes connected to this node       |
| **Field rules**        | rule editor | No       | Per-field comparisons between Source A and Source B (see below)                              |
| **Compare line items** | toggle      | No       | Enable row-by-row comparison of two arrays (see below)                                       |
| **Carry forward**      | select      | Yes      | Which source becomes the step output that flows downstream                                   |

## Field rules

Each rule compares a single value on Source A against the matching value on Source B. The rule editor has these columns:

| Column        | Description                                                                 |
| ------------- | --------------------------------------------------------------------------- |
| **Source A**  | A field reference, for example `{{total}}`, relative to the chosen Source A |
| **Source B**  | The matching field reference, relative to the chosen Source B               |
| **Compare**   | The comparison method (see below)                                           |
| **Severity**  | `Block` or `Warn` (see below)                                               |
| **Tolerance** | Shown only for numeric tolerance comparisons                                |

The editor validates that the referenced paths exist on the chosen source and that the two sides resolve to the same type.

## Comparison methods

| Method                           | Behavior                                                                                   |
| -------------------------------- | ------------------------------------------------------------------------------------------ |
| **Exact**                        | The two values must match exactly                                                          |
| **Numeric tolerance (%)**        | The two numbers must be within a percentage of each other. Requires a positive tolerance   |
| **Numeric tolerance (absolute)** | The two numbers must be within a fixed amount of each other. Requires a positive tolerance |
| **Date equals**                  | The two values must be the same calendar date                                              |
| **Normalized text**              | The two text values must match ignoring case and extra spacing                             |

The methods offered depend on the field type:

* **Number** gives **Exact** plus the two numeric tolerances.
* **String** gives **Exact**, **Normalized text**, and **Date equals**.
* **Boolean** gives **Exact** only.

## Severity

| Severity  | Behavior                                                      |
| --------- | ------------------------------------------------------------- |
| **Block** | A blocking mismatch that stops auto-approval and needs review |
| **Warn**  | Recorded as a warning but still auto-approves                 |

## Compare line items

Enable **Compare line items** to match rows between two arrays (for example line items) and compare columns within each matched row.

| Field                           | Required | Description                                                                                                                                                                                                                                                 |
| ------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Source A array path**         | Yes      | The array to compare on Source A, for example `{{line_items}}`                                                                                                                                                                                              |
| **Source B array path**         | Yes      | The array to compare on Source B, for example `{{line_items}}`                                                                                                                                                                                              |
| **Row matching**                | Yes      | `By position` pairs rows by their order in each list. `By key (all fields)` matches rows that share the same value in every key field, in any order. `By key (in priority order)` does the same, then retries the leftovers on fewer key fields (see below) |
| **Severity for unmatched rows** | Yes      | The severity for a row present on one source with no match on the other                                                                                                                                                                                     |
| **Column rules**                | Yes      | At least one column rule is required when line items are enabled. Each column rule uses the same **Source A**, **Source B**, **Compare**, **Severity**, and **Tolerance** shape as field rules                                                              |

### Matching by key in priority order

`By key (all fields)` pairs two rows only when every key field matches. A row whose mark is right but
whose width was read a millimetre off stays unmatched, even when it is obviously the same line.

`By key (in priority order)` treats the key fields as a priority list, ordered by dragging them, and
works down it:

1. First it pairs every row that matches on **all** key fields. Anything the all-fields strategy
   would have found is still found here, so this strategy never pairs fewer rows.
2. Then it retries the rows left over on **fewer** key fields, dropping the last one each round. With
   keys `mark`, `width`, `height` that means a round on `mark` + `width`, then a round on `mark`
   alone.
3. In those later rounds it pairs two rows only when **exactly one row is left on each side** for
   that value. If two rows still share the same mark and one candidate is left, none of them pair.

So with keys `mark` then `width`, a document row `mark A-12, width 1200` pairs with a record row
`mark A-12, width 1199` as long as A-12 is the only one left on each side. A pair made this way is a
full pair: the widths disagreeing is not reported anywhere.

<Note>
  To have a field checked but not required for pairing, list it as a key field **and** add it as a
  column rule. Key fields are matched as exact text, while a column rule gives you a comparison type
  and a tolerance, so `1200` and `1200.00` can count as equal.
</Note>

## Carry forward

Choose **Source A** or **Source B**. The chosen source becomes the step output that flows downstream, while the other source is the record written back to.

## Output

The output is the carried-forward source payload plus a `metadata.reconciliation` object:

| Field                | Type    | Description                                  |
| -------------------- | ------- | -------------------------------------------- |
| `overallMatch`       | boolean | `true` when there are no blocking mismatches |
| `blockMismatchCount` | number  | The number of blocking mismatches found      |
| `warnMismatchCount`  | number  | The number of warning mismatches found       |

The node auto-approves when there are no blocking mismatches.

## Routing mismatches to review

To pause only the runs that disagree out of tolerance, add a [Review](/nodes/review) node after Reconcile and set its pause mode to **Reconcile mismatch**. Runs whose reconciliation result has no blocking mismatches continue automatically; only runs with out-of-tolerance results pause for a reviewer.

## Inputs and outputs

**Allowed inputs:** Reconcile requires two upstream sources.

**Output:** The carried-forward payload with the reconciliation result in `metadata`.

## Common pitfalls

<AccordionGroup>
  <Accordion title="A reconcile node with no rules always auto-approves">
    With no field rules and no line-item column rules, there is nothing to compare, so every run auto-approves. The editor requires at least one field rule or line-item column rule before you can save.
  </Accordion>

  <Accordion title="Numeric tolerance with a blank or zero tolerance">
    A numeric tolerance of blank or `0` collapses to an exact match, which is almost never what you want for amounts. The editor rejects a numeric tolerance comparison without a positive tolerance.
  </Accordion>

  <Accordion title="Compare line items enabled with no column rule">
    Turning on **Compare line items** without adding a column rule compares nothing inside the matched rows. At least one column rule is now required when line items are enabled.
  </Accordion>

  <Accordion title="Reconcile mismatch on a Review node with no Reconcile predecessor">
    The **Reconcile mismatch** pause mode only fires when a Reconcile node sits upstream of the [Review](/nodes/review) node. The editor hides or rejects this pause mode when no Reconcile predecessor is connected.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Review action" icon="user-check" href="/nodes/review">
    Pause for review when sources disagree
  </Card>

  <Card title="Extract action" icon="sparkles" href="/nodes/extract">
    Extract structured data before reconciling
  </Card>

  <Card title="HTTP action" icon="globe" href="/nodes/http-action">
    Fetch a system of record to compare against
  </Card>

  <Card title="Validation" icon="circle-check" href="/nodes/validation">
    Validate data with rules before delivery
  </Card>
</CardGroup>
