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

# Split and aggregate matches

> Reconcile 1:1, 1:N (split and aggregate), and N:M transaction patterns using context types and rule allocation flags to control how amounts are distributed.

Real-world reconciliation often involves transactions that don't match 1:1. A single payment may cover multiple invoices, or several deposits may consolidate into one bank entry. Matcher handles these complex scenarios through split and aggregate matching.

## Overview

***

The **context type** controls matching cardinality. Matcher supports three context types:

| Context type                        | Description                                                                          | Example                                                         |
| ----------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------- |
| **1:1** — one to one                | One source to one target                                                             | Single invoice payment                                          |
| **1:N** — one to many / many to one | One source to many targets (**split**) or many sources to one target (**aggregate**) | Bulk payment covering invoices; deposits consolidated at a bank |
| **N:M** — many to many              | Any combination of sources and targets                                               | Complex netting                                                 |

<Note>
  There is no separate `N:1` context type. Aggregate matching (many sources to one target) uses the `1:N` context type in the aggregate direction. The same context type covers both split and aggregate.
</Note>

## How it works

***

Two mechanisms control split and aggregate behavior:

1. **Context type**: determines the matching cardinality (`1:1`, `1:N`, or `N:M`).
2. **Rule allocation flags**: control how Matcher distributes amounts within a match group.

There is no separate "split" or "aggregate" setting on the context. The context type defines the allowed patterns, and the rule config controls allocation behavior.

### Context type mapping

| Context type | Allowed patterns                                                              |
| ------------ | ----------------------------------------------------------------------------- |
| `1:1`        | One source to one target only                                                 |
| `1:N`        | One source to many targets (split), or many sources to one target (aggregate) |
| `N:M`        | Any combination of sources and targets                                        |

### Rule allocation settings

All rule types accept allocation flags in their `config`:

| Field                      | Type    | Description                                                                                                                                                                                                           |
| -------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `allowPartial`             | Boolean | Allow partial allocation of transaction amounts                                                                                                                                                                       |
| `allocationDirection`      | String  | Allocation order: `LEFT_TO_RIGHT` or `RIGHT_TO_LEFT`                                                                                                                                                                  |
| `allocationToleranceMode`  | String  | How tolerance is measured: `ABS` (absolute) or `PERCENT`                                                                                                                                                              |
| `allocationToleranceValue` | Decimal | Tolerance threshold for allocation residuals                                                                                                                                                                          |
| `allocationUseBaseAmount`  | Boolean | Use base (converted) amount for allocation                                                                                                                                                                            |
| `feeAware`                 | Boolean | Fee-aware 1:N allocation: consume each candidate's gross share (net + fee) instead of net only. Useful for marketplace splits where the payout is net of fees                                                         |
| `nmDeductionBand`          | Decimal | TOLERANCE rules only. Short-pay band for the N:M solver, as a decimal fraction of the short invoice face (`0.05` = 5%). Lets a payment subset under-pay an invoice subset within the band. Zero or absent disables it |

### Example: tolerance rule with allocation

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts/{contextId}/rules" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "type": "TOLERANCE",
   "priority": 2,
   "config": {
     "percentTolerance": 0.01,
     "absTolerance": 5.0,
     "matchCurrency": true,
     "allowPartial": true,
     "allocationDirection": "LEFT_TO_RIGHT",
     "allocationToleranceMode": "ABS",
     "allocationToleranceValue": 10.0,
     "matchScore": 85,
     "matchBaseScore": 80
   }
 }'
```

<Note>
  Matcher accepts and validates `matchScore` and `matchBaseScore`. Both keys remain **reserved/inert**. They do not change the calculated confidence score. Matcher always computes confidence from the fixed internal component weights (amount 40, currency 30, date 20, reference 10). See [Confidence scoring](/en/products/matcher/reference/matcher-confidence-scoring).
</Note>

## Creating a 1:N context

***

To enable split or aggregate matching, create a context with type `1:N`:

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Payment Reconciliation",
   "type": "1:N",
   "interval": "daily"
 }'
```

<Tip>
  API Reference: [Create context](/en/reference/products/matcher/create-context)
</Tip>

## 1:N split matching

***

One source transaction matches multiple target transactions.

### Common use cases

* **Bulk payment**: Single wire covering multiple invoices
* **Payroll**: One bank debit for multiple salary payments
* **Settlement**: One gateway payout for multiple orders

### Example: bulk invoice payment

**Source (Bank Statement):**

| ID        | Amount      | Reference         |
| --------- | ----------- | ----------------- |
| bank\_001 | \$15,000.00 | BULK-PAY-2024-001 |

**Targets (Ledger Entries):**

| ID       | Amount     | Invoice      |
| -------- | ---------- | ------------ |
| inv\_001 | \$5,000.00 | INV-2024-001 |
| inv\_002 | \$7,500.00 | INV-2024-002 |
| inv\_003 | \$2,500.00 | INV-2024-003 |

**Result:** 1:3 match with full allocation

## Aggregate matching (many-to-one)

***

Multiple source transactions match one target transaction. This is the aggregate direction of the `1:N` context type. It is not a separate `N:1` type.

### Common use cases

* **Bank deposits**: Multiple checks deposited as one credit
* **Card settlements**: Daily batch of transactions as one deposit
* **Cash consolidation**: Multiple register receipts to one deposit

### Example: consolidated deposit

**Sources (Point of Sale):**

| ID       | Amount     | Register |
| -------- | ---------- | -------- |
| pos\_001 | \$1,250.00 | REG-01   |
| pos\_002 | \$980.00   | REG-02   |
| pos\_003 | \$1,770.00 | REG-03   |

**Target (Bank Statement):**

| ID        | Amount     | Reference        |
| --------- | ---------- | ---------------- |
| bank\_002 | \$4,000.00 | DEPOSIT-20240120 |

**Result:** 3:1 match with full allocation

## N:M many-to-many matching

***

Multiple source transactions match multiple target transactions. This is the most complex pattern.

### Common use cases

* **Intercompany netting**: Multiple invoices netted against multiple payments
* **Trade settlements**: Complex clearing with partial fills
* **Revenue recognition**: Multiple deliveries against multiple advances

### Example: intercompany netting

**Sources (Company A Payables):**

| ID       | Amount      | Reference  |
| -------- | ----------- | ---------- |
| pay\_001 | \$10,000.00 | IC-PAY-001 |
| pay\_002 | \$8,000.00  | IC-PAY-002 |

**Targets (Company A Receivables):**

| ID       | Amount      | Reference  |
| -------- | ----------- | ---------- |
| rec\_001 | \$12,000.00 | IC-REC-001 |
| rec\_002 | \$6,000.00  | IC-REC-002 |

**Result:** 2:2 match, \$18,000 total matched

To enable N:M matching, create a context with type `N:M`:

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Intercompany Netting",
   "type": "N:M",
   "interval": "weekly"
 }'
```

## Running and reviewing matches

***

After configuring the context and rules, trigger a matching run and review the resulting groups.

### Run matching

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/matching/contexts/{contextId}/run" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "mode": "DRY_RUN"
 }'
```

### View match run history

```bash cURL theme={null}
curl -X GET "https://api.matcher.example.com/v1/matching/contexts/{contextId}/runs" \
 -H "Authorization: Bearer $TOKEN"
```

### View a run's match groups

You must send the `contextId` query parameter. The response is a cursor-paginated list of match groups, each containing its matched transactions (across all cardinalities) and confidence scores.

```bash cURL theme={null}
curl -X GET "https://api.matcher.example.com/v1/matching/runs/{runId}/groups?contextId={contextId}" \
 -H "Authorization: Bearer $TOKEN"
```

### Break (unmatch) a match group

To reverse an incorrect group, unmatch it. Matcher rejects a `PROPOSED` group with a reason, and its transactions return to `UNMATCHED`. For a `CONFIRMED` group, Matcher also reverses the residual/open-item effects that confirmation applied, atomically with revoking the group and returning its transactions. You must send the `contextId` query parameter and a `reason` in the body.

```bash cURL theme={null}
curl -X DELETE "https://api.matcher.example.com/v1/matching/groups/{matchGroupId}?contextId={contextId}" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "reason": "incorrect match - amounts do not match"
 }'
```

If the confirmed group's reversal removes the final live contribution behind an obligation, that open item becomes terminal `WITHDRAWN`. It remains as history, but it is not nettable and no other run carries it. Matcher checks reversibility before changing anything. The endpoint returns `409 Conflict` if a later live entry still stands on the residual. It also returns that error if a newer live obligation would conflict with restoring a terminal item on the same identity. In both cases it leaves the group, transactions, and open items unchanged.

## Matching algorithm

***

The algorithm depends on the context type.

### 1:N deterministic sequential allocation

For split and aggregate (`1:N`) scenarios, Matcher uses deterministic sequential allocation:

1. **Sort**: Matcher sorts transactions deterministically to ensure reproducible results across runs.
2. **Iterate**: The engine walks through candidates in priority order.
3. **Allocate**: Matcher distributes amounts according to the `allocationDirection` setting (`LEFT_TO_RIGHT` or `RIGHT_TO_LEFT`).
4. **Track residuals**: Matcher tracks any remaining unallocated amounts. If `allowPartial` is `true`, Matcher caps an overshooting leg to the remaining amount. An under-covered split still surfaces a diagnostic exception.

### N:M set-matching solver

For `N:M` scenarios, Matcher does **not** allocate sequentially. It uses a bounded subset-selection solver. The solver buckets candidates by the rule's match identity. It then searches for a subset of left transactions and a subset of right transactions that reconcile against each other. The solver caps cardinality per side.

Selection remains deterministic over the sorted input. Each proposed group must clear the fixed confidence gate (minimum score 60). No transaction lands in two proposed groups within a run. On TOLERANCE rules, the `nmDeductionBand` key lets the solver admit a payment subset that under-pays an invoice subset within the band.

### Exception reasons

Transactions that Matcher cannot fully reconcile surface as typed exceptions:

* `SPLIT_INCOMPLETE`: allocations exist but do not fully cover the target amount, regardless of `allowPartial`.
* `OVER_SETTLED`: a leg over-shot what it settled. Matcher surfaces the over-settled remainder as a typed break.

You can filter the exceptions list by these `reason` values.

## Best practices

***

<AccordionGroup>
  <Accordion title="Start with 1:N before N:M">
    Many-to-many matching is complex. Start with simpler patterns and enable N:M only when necessary.
  </Accordion>

  <Accordion title="Use allocation tolerance for rounding">
    Small rounding differences are common in split payments. Set allocationToleranceValue to a few cents to avoid false exceptions.
  </Accordion>

  <Accordion title="Enable partial allocation deliberately">
    Set allowPartial to true only when you expect partial matches. This prevents false matches from incomplete data.
  </Accordion>

  <Accordion title="Dry-run before committing">
    Always test split and aggregate matching in DRY\_RUN mode first to verify allocation results.
  </Accordion>

  <Accordion title="Monitor residuals">
    Track residual amounts over time. Growing residuals may indicate systematic matching issues.
  </Accordion>
</AccordionGroup>

## Next steps

***

<Card title="Match Rules" icon="scale-balanced" href="/en/products/matcher/configuration/matcher-match-rules" horizontal>
  Configure rules and allocation settings.
</Card>

<Card title="Security" icon="shield-halved" href="/en/products/matcher/reference/matcher-security" horizontal>
  Security and access control.
</Card>
