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

# Reviewing matches

> Review matches after a run. Understand the 0–100 confidence score, its four weighted components, variance causes, and how to confirm, reject or revoke a match group.

After running a matching job, review the results. This guide explains how to interpret match results, understand confidence scores, and confirm, reject or revoke match groups.

## Match status lifecycle

***

Matches progress through a defined lifecycle:

* When the matching engine finds a pair of transactions that belong together, it creates a match in `PROPOSED` status.
* Engine-created matches that score 90 or above from EXACT and TOLERANCE rules are auto-confirmed immediately. Manual matches, created with `POST /v1/matching/manual`, start in `CONFIRMED` status. FUZZY and DATE\_LAG matches remain `PROPOSED` and are never auto-confirmed.
* Matches that are not auto-confirmed remain in `PROPOSED`. You can confirm a proposed group with the confirm operation, or reject it with the unmatch operation and a required reason.
* Rejecting a `PROPOSED` group returns its transactions to the unmatched pool, except a transaction that you force-matched separately: it stays `MATCHED`. Revoking a `CONFIRMED` group returns every transaction. The status change and the transaction return happen atomically.
* When Matcher changes the status of a match's transactions, it changes all of them or none. A manual match that loses a race on a transaction gets `409`, and Matcher applies nothing.

> [!NOTE]
>
> **FUZZY and DATE\_LAG matches are never auto-confirmed.** Auto-confirmation at score ≥ 90 applies to engine-created EXACT and TOLERANCE matches. A manual match starts in `CONFIRMED` status. A match produced by a FUZZY or DATE\_LAG rule stays in `PROPOSED`, regardless of its score, even when it scores 90+. You can confirm it with the confirm operation or reject it through the unmatch operation. See [Confidence scoring](https://docs.lerian.studio/en/products/matcher/reference/matcher-confidence-scoring.md#rule-types-that-never-auto-confirm).

![Match Status Lifecycle](https://mintcdn.com/lerian-49cb71fc/-JdEHn8RRUgJwJCQ/images/en/d2/matcher-match-status.svg?fit=max\&auto=format\&n=-JdEHn8RRUgJwJCQ\&q=85\&s=c7160bc0fa7ceb175c62676d36bcfb88)

Status lifecycle of a match.

### Status definitions

| Status | Description | Next Actions |
| - | - | - |
| `PROPOSED` | Match identified by the system but not confirmed | Confirm through the confirm operation, or reject through the unmatch operation |
| `CONFIRMED` | Match was auto-confirmed, confirmed by a reviewer, or created as a manual match | Revoke through the unmatch operation if incorrect |
| `REJECTED` | Match was declined | Transactions return to unmatched pool, except a force-matched transaction |
| `REVOKED` | A previously confirmed match was revoked | Transactions return to unmatched pool |

## Confidence tiers

***

Matcher assigns a confidence score (0-100) to each proposed match. The score determines what happens to the match.

### Confidence levels

| Tier | Score range | Behavior |
| - | - | - |
| Auto-confirm eligible | 90-100 | Engine-created EXACT and TOLERANCE matches are automatically confirmed without manual review. Manual matches are created `CONFIRMED`. FUZZY and DATE\_LAG matches remain `PROPOSED`. |
| Needs Review | 60-89 | Medium confidence matches remain `PROPOSED`. You can review them, then confirm or reject them. |

### Understanding the score

Matcher calculates the confidence score from weighted components:

| Component | Weight | What it Measures |
| - | - | - |
| Amount match | 40% | How closely transaction amounts align |
| Currency match | 30% | Whether currencies are the same |
| Date tolerance | 20% | How close the transaction dates are |
| Reference match | 10% | Whether transaction references match |

**Example Score Breakdown:**

```
Match: BANK-001 ↔ LED-001

Amount: $1,000.00 vs $1,000.00 → 100% × 40% = 40 points
Currency: USD vs USD → 100% × 30% = 30 points
Date: 2024-01-15 vs 2024-01-15 → 100% × 20% = 20 points
Reference: PAY-001 vs PAY-001 → match → 10 points
 ─────────────────────────
Total Confidence: 100 points
```

## Understanding variances

***

When matches have differences, review the variance details:

### Amount variance

Common causes of amount variance:

* Bank fees
* Currency conversion differences
* Rounding differences
* Partial payments

### Date variance

Common causes of date variance:

* Settlement timing
* Time zone differences
* Posting vs. transaction date
* Weekend/holiday processing

## Match candidates, open items, and adjustments

***

Matcher gives you three surfaces for working a review queue: match candidates, open items, and adjustments.

### List match candidates

Retrieve the ranked counterpart candidates for a transaction, highest score first. Each candidate carries its confidence score, the rule that produced the score, and the amount and date differences. Its `why` object shows which fields agree.

```bash cURL theme={null}
curl -X GET "https://api.matcher.example.com/v1/matching/candidates?contextId={contextId}&transactionId={transactionId}&limit=20" \
 -H "Authorization: Bearer $TOKEN"
```

`GET /v1/matching/candidates` accepts `contextId`, `transactionId`, and `limit` query parameters and returns a `CandidateProposalsResponse`. The `limit` defaults to 50 and accepts values from 1 to 200.

The candidate picker scans at most 5,000 unmatched transactions in the context and returns only 1:1 candidates from the opposite side. It applies the shared scorer to raw transaction data, without the run-time fee normalization or FX variance-band matching used by a matching run.

### List open items

Open items are residual balances that remain when a transaction nets only in part. Track them to surface amounts that still need clearing or that have aged past their threshold.

```bash cURL theme={null}
curl -X GET "https://api.matcher.example.com/v1/matching/contexts/{contextId}/open-items?status=OPEN&limit=50" \
 -H "Authorization: Bearer $TOKEN"
```

`GET /v1/matching/contexts/{contextId}/open-items` supports a `status` filter, plus `limit`/`cursor` pagination.

#### Open item statuses

| Status | When it occurs |
| - | - |
| `OPEN` | Fresh residual. The item has a remaining balance and no leg has netted against it yet. |
| `PARTIALLY_CLEARED` | At least one leg has netted against the balance, but a residual still remains. |
| `CLEARED` | The residual has been fully netted within tolerance. |
| `AGED` | The item remained open beyond its aging threshold, measured from the obligation business date or the legacy first-seen time. |
| `WITHDRAWN` | An un-match took back the confirmed match that created the obligation. |

The normal lifecycle flows `OPEN` → `PARTIALLY_CLEARED` → `CLEARED`, with any still-open item able to become `AGED` once it passes the aging threshold. `WITHDRAWN` is terminal.

### Create an adjustment

Post an accounting adjustment to account for a variance (bank fee, FX difference, rounding, write-off, and so on) against a match group or transaction.

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/matching/adjustments?contextId={contextId}" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "amount": "10.50",
   "currency": "BRL",
   "direction": "DEBIT",
   "type": "BANK_FEE",
   "reason": "Variance due to bank processing fee",
   "description": "Bank wire fee adjustment",
   "matchGroupId": "019c96a0-0b74-768c-8d25-2bf065dca2f8"
 }'
```

`POST /v1/matching/adjustments` requires the `contextId` query parameter. Body fields:

**amount** `String` *required*

Adjustment amount

**currency** `String` *required*

Three-character currency code.

**direction** `String` *required*

`DEBIT` or `CREDIT`

**type** `String` *required*

`BANK_FEE`, `FX_DIFFERENCE`, `ROUNDING`, `WRITE_OFF`, or `MISCELLANEOUS`

**reason** `String` *required*

Business reason for the adjustment

**description** `String` *required*

Human-readable description

**matchGroupId** `UUID`

Match group the adjustment applies to

**transactionId** `UUID`

Transaction the adjustment applies to

Send at least one of `matchGroupId` or `transactionId`.

To read the adjustments recorded against a context, use `GET /v1/matching/contexts/{contextId}/adjustments`. It accepts an optional `matchGroupId` filter, and pages with `cursor`.

> [!TIP]
>
> API Reference:
>
> * [List match candidates](https://docs.lerian.studio/en/reference/products/matcher/list-match-candidates.md)
> * [List open items](https://docs.lerian.studio/en/reference/products/matcher/list-open-items.md)
> * [Create adjustment](https://docs.lerian.studio/en/reference/products/matcher/create-adjustment.md)

## Confirming a proposed match group

***

Use the **confirm** operation to approve a `PROPOSED` group in one step. Only the `operator` and `admin` roles can confirm.

Use `POST /v1/matching/groups/{matchGroupId}/confirm` with the required `contextId` query parameter (operationId `confirmMatchGroup`):

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

A successful confirm returns **200** with the match group.

### What happens after confirm

1. **Match status changes**: The group becomes `CONFIRMED`. It keeps the rule and the confidence score that the engine gave it.
2. **Transactions matched**: Its transactions become `MATCHED`.
3. **Variances recorded**: Matcher records fee variances, open-item residuals and exception closures as it does for an auto-confirmed group.
4. **Audit entry written**: A `CONFIRM` entry records who confirmed the group. The confirm does not commit without it.
5. **Streaming events emitted**: Matcher emits `match_group.confirmed`, and `transaction.matched` for its transactions. See [Matcher events](https://docs.lerian.studio/en/reference/events/matcher.md).
6. **Reversal possible**: A later unmatch reverses a confirmed group.

A group that is no longer `PROPOSED` returns `409` with code `MTCH-0007`, and nothing changes. The same code answers when a transaction of the group changed after the proposal.

> [!NOTE]
>
> Lerian Console does not offer a Confirm control. Confirm a proposed group through the API.

## Rejecting or revoking match groups

***

Use the **unmatch** operation to reject a `PROPOSED` group or revoke a `CONFIRMED` group. After a successful operation, Matcher returns the group's transactions to `UNMATCHED`. When you reject a `PROPOSED` group, a transaction that you force-matched separately stays `MATCHED`. The next run can match them again.

Use `DELETE /v1/matching/groups/{matchGroupId}` with the required `contextId` query parameter and a `reason` in the request body (operationId `unmatch`):

```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"
 }'
```

A successful unmatch returns **204 No Content**. The `reason` field is mandatory and must not be empty. The request accepts an optional `X-Idempotency` header. Unmatching a group that is already rejected or revoked returns `409` with code `MTCH-0007`.

### When to reject or revoke

Common scenarios for rejecting or revoking a group:

* **Incorrect match confirmed**: the transactions in a confirmed group belong to different records
* **New information**: Additional data shows the match is wrong
* **Source correction**: The source system issued a correction or reversal
* **Duplicate transaction**: one of the transactions is a duplicate that you should remove

### What happens after unmatch

When you unmatch a match group:

1. **Match status changes**: A `CONFIRMED` group becomes `REVOKED`. A still-`PROPOSED` group becomes `REJECTED`.
2. **Transactions returned**: The associated transactions revert to `UNMATCHED` status atomically with the status change. When you reject a `PROPOSED` group, a transaction that you force-matched separately stays `MATCHED`.
3. **Confirmed effects withdrawn**: For a `CONFIRMED` group, Matcher also withdraws its open-item residuals, voids its fee variances, and withdraws the exceptions it raised. If a manual or automatic match closed an exception, Matcher marks that exception `UNMATCH_WITHDRAWN`, and the next exception that Matcher raises on the transaction reopens it. These changes and the status change happen in one transaction.
4. **Reason recorded**: The group stores the supplied rejection or revocation reason.
5. **Streaming event emitted**: A `match_group.unmatched` event is emitted only when the group was previously `CONFIRMED`.
6. **Re-matching possible**: after a successful unmatch, the next run can match the transactions again.

## Best practices

***

> [accordion] Start with lowest confidence matches
>
> Review matches with the lowest confidence scores first. These matches are the most likely to be wrong. Give them the most attention.

> [accordion] Understand fixed confidence thresholds
>
> The confidence thresholds do not change. Engine-created EXACT and TOLERANCE matches with scores of 90 or above are auto-confirmed. Manual matches start `CONFIRMED`. Scores between 60 and 89 remain `PROPOSED`. These values are not configurable per context.
>
> **FUZZY and DATE\_LAG matches are the exception. They are never auto-confirmed and remain `PROPOSED`, regardless of score.**
>
> Use rule tuning (priority, tolerance values) to influence how many matches land in each tier.

> [accordion] Give a clear reason
>
> Provide a specific reason when rejecting a proposed group or revoking a confirmed group. The unmatch operation requires it and stores it with the group.

> [accordion] Reject only after checking the source data
>
> Review the group and its source transactions before using the unmatch operation. Matcher exposes this operation and the confirm operation per group. It does not expose bulk confirmation.

> [accordion] Review high-value matches carefully
>
> Regardless of confidence score, give extra attention to high-value matches. The impact of an incorrect match is proportional to the amount.

## Next steps

***

> [card] [Resolving exceptions](https://docs.lerian.studio/en/products/matcher/daily-reconciliation/matcher-resolving-exceptions.md)
>
> Handle transactions with no automatic match.

> [card] [Confidence scoring](https://docs.lerian.studio/en/products/matcher/reference/matcher-confidence-scoring.md)
>
> Learn in detail how Matcher calculates confidence scores.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.