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

# Contexts and sources

> Set up a reconciliation context and its sources in Matcher — pick 1:1, 1:N, or N:M cardinality, add bank and ledger feeds, and trigger match runs.

Contexts and sources are how you tell Matcher **what** to reconcile and **where the numbers come from**. They are the two building blocks you set up before any matching happens.

* A **context** is a single reconciliation you care about — for example, *"our main bank account vs. our books."* It sets the scope: which systems are compared, which rules apply, and over what period.
* A **source** is one of the systems feeding numbers into that comparison — a bank statement, an ERP export, a payment processor's settlement file, or a ledger.

Every context compares exactly two sides against each other, so each one needs at least two sources. Get these right and everything downstream — matching, exceptions, and reporting — follows.

## What is a reconciliation context?

***

A reconciliation context defines the operational boundaries of a reconciliation process.
It specifies:

* Which data sources are compared
* Which matching rules apply
* How exceptions are handled
* The time window covered by reconciliation

**Common examples:**

* *Bank Account 1234 vs General Ledger* (daily bank reconciliation)
* *Payment Gateway vs Revenue System* (payment reconciliation)
* *Intercompany Entity A vs Entity B* (intercompany reconciliation)

## Context types

***

Matcher lets you use different reconciliation cardinalities based on transaction structure.

### One-to-one (1:1)

Each transaction is reconciled against a single counterpart.

**Typical use cases:**

* Bank statements
* Direct payment matching

### One-to-many (1:n)

One transaction is reconciled against multiple counterparts.

**Typical use cases:**

* Split payments
* Batch deposits
* Consolidated invoices

### Many-to-many (n:m)

Multiple transactions are reconciled across multiple counterparts.

**Typical use cases:**

* Netting arrangements
* Complex payment allocation
* Multi-leg financial flows

## Creating a reconciliation context

***

Once you know what you're reconciling, create the context. At this stage you're mainly declaring the cardinality (`type`), a required execution label (`interval`), and any fee tolerance the comparison should allow. The `interval` value does not schedule runs; automatic execution requires a separate [reconciliation schedule](/en/matcher/configuration/matcher-schedules). A new context starts in `DRAFT` and remains there until you explicitly activate it.

#### Request

```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": "Daily Bank Reconciliation",
   "interval": "daily",
   "type": "1:1",
   "feeToleranceAbs": "0",
   "feeTolerancePct": "0",
   "feeNormalization": "NET",
   "autoMatchOnUpload": false
 }'
```

#### Context fields

<ParamField path="name" type="string">
  Descriptive name for the context
</ParamField>

<ParamField path="type" type="string">
  Matching cardinality: `1:1`, `1:N`, or `N:M`
</ParamField>

<ParamField path="interval" type="string">
  Required execution label (e.g. `daily`, `weekly`). It does not schedule runs.
</ParamField>

<ParamField path="feeToleranceAbs" type="string" default="0">
  Absolute fee tolerance for amount comparison, as a decimal string (e.g. `"0.01"`)
</ParamField>

<ParamField path="feeTolerancePct" type="string" default="0">
  Percentage fee tolerance for amount comparison, as a decimal string (`"0.5"` means 0.5%)
</ParamField>

<ParamField path="feeNormalization" type="string">
  Optional fee normalization mode: `NET` or `GROSS`. Omit it to leave fee normalization disabled.
</ParamField>

<ParamField path="autoMatchOnUpload" type="boolean" default="false">
  Automatically trigger a match run when a file is uploaded
</ParamField>

#### Response

```json theme={null}
{
  "id":"019c96a0-2a10-7dfe-b5c1-8a1b2c3d4e5f",
  "tenantId":"11111111-1111-1111-1111-111111111111",
  "name":"Daily Bank Reconciliation",
  "type":"1:1",
  "interval":"daily",
  "status":"DRAFT",
  "feeToleranceAbs":"0",
  "feeTolerancePct":"0",
  "feeNormalization":"NET",
  "autoMatchOnUpload":false,
  "createdAt":"2026-02-02T16:31:22Z",
  "updatedAt":"2026-02-02T16:31:22Z"
}
```

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

## Running reconciliation

***

A context doesn't reconcile on its own — you trigger a **match run**. A run applies the context's active rules to the transactions in its sources, then produces matches and exceptions. You can trigger runs by hand, or let a [schedule](/en/matcher/configuration/matcher-schedules) fire them automatically.

Every run works in one of two modes:

| Mode      | What it does                                                                                                                                       |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DRY_RUN` | Does not persist matching results, transaction mutations, fee artifacts, or exceptions, but does persist a completed `MatchRun` and its statistics |
| `COMMIT`  | Executes matching and persists the results                                                                                                         |

Trigger a run for a context:

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

By default a run is **synchronous** — it executes in-request and the response carries the final status. For large volumes, set `"async": true` to submit the run and poll its progress instead. Asynchronous submission requires the match-run worker to be enabled; otherwise Matcher rejects `"async": true` with HTTP 503.

<Info>
  Both modes return **HTTP 202 Accepted**, so read the response `status`, not the HTTP code, to know the outcome.

  A synchronous run returns a terminal `COMPLETED` or `FAILED`; an async run returns `QUEUED`, and you poll `GET /v1/matching/runs/{runId}`.

  While in flight, a run moves through `PROCESSING` and `FINALIZING` (treat both as not-yet-done) before reaching `COMPLETED` or `FAILED`.
</Info>

To review past runs, list a context's run history with `GET /v1/matching/contexts/{contextId}/runs`.

<Tip>
  API Reference:

  * [Run match](/en/reference/matcher/run-match)
  * [List match runs](/en/reference/matcher/list-match-runs)
</Tip>

## What is a source?

***

A source represents a system or data feed that supplies transactions to a reconciliation context.
Each context requires at least two sources.

**Typical sources include:**

* Bank statement feeds
* ERP general ledger exports
* Payment processor transaction streams
* Internal accounting systems

## Adding sources to a context

***

A context needs at least two sources — one for each side of the comparison. The `side` field (`LEFT` or `RIGHT`) declares which side a source feeds; Matcher reconciles the `LEFT` side against the `RIGHT` side. Assign one side to each source and keep the assignment consistent.

Create a source with a `name`, `type`, `side`, and a `config` object. Leave `config` empty (`{}`) when the source needs no connection-specific settings — as with a bank feed on the `LEFT` side:

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts/{contextId}/sources" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Chase Bank - Account 1234",
   "type": "BANK",
   "side": "LEFT",
   "config": {}
 }'
```

Point the other side at a second source. `config` carries source-specific connection and parsing settings when they're needed — for example a payment gateway on the `RIGHT` side:

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts/{contextId}/sources" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Payment Gateway",
   "type": "GATEWAY",
   "side": "RIGHT",
   "config": {
     "currency": "USD",
     "provider": "stripe"
   }
 }'
```

<Info>
  `name`, `type`, and `side` are required (`name` is 1–50 characters). `config` is optional and defaults to an empty object when omitted.
</Info>

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

### Source types

| Type      | Description             | Typical use                                              |
| --------- | ----------------------- | -------------------------------------------------------- |
| `LEDGER`  | Internal ledger         | Internal accounting systems (including Midaz)            |
| `BANK`    | Bank statement feed     | External bank feeds                                      |
| `GATEWAY` | Payment gateway         | Payment processors (Stripe, Adyen, PayPal)               |
| `CUSTOM`  | Bespoke feed            | Any other data source                                    |
| `FETCHER` | Discovery-engine source | Aggregator connections supplied through a source binding |

### Fetcher sources

`FETCHER` identifies a source type; it does not enable automatic pulling by itself. Create it like any other source, then wire the upstream aggregator connection through a [source binding](#source-bindings) on the query rail (`connectionId`) — see [Discovery](/en/matcher/integrations/matcher-discovery) for how connections are set up.

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts/{contextId}/sources" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Open Banking Aggregator",
   "type": "FETCHER",
   "side": "LEFT",
   "config": {
     "provider": "pluggy"
   }
 }'
```

## Managing sources

***

Sources support a full CRUD lifecycle under `/v1/contexts/{contextId}/sources`. You can rename or reconfigure a source at any time, and **archiving is soft and reversible**. An archived source is excluded from context readiness, matching, and source listings, but keeps its full history until you restore it. Archiving does not disable its bindings; disable or delete them separately to stop scheduler dispatch.

| Action         | Method & path                                              | Notes                                                                                                         |
| -------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Create source  | `POST /v1/contexts/{contextId}/sources`                    | Body: `name`, `type`, `side`, `config` (see above).                                                           |
| List sources   | `GET /v1/contexts/{contextId}/sources`                     | Lists sources in the context.                                                                                 |
| Get source     | `GET /v1/contexts/{contextId}/sources/{sourceId}`          | Retrieves a single source by id.                                                                              |
| Update source  | `PATCH /v1/contexts/{contextId}/sources/{sourceId}`        | Updates mutable source fields (e.g. `name`, `config`).                                                        |
| Archive source | `POST /v1/contexts/{contextId}/sources/{sourceId}/archive` | Excludes the source from readiness, matching, and listings; bindings remain enabled until changed separately. |
| Restore source | `POST /v1/contexts/{contextId}/sources/{sourceId}/restore` | Reactivates a previously archived source.                                                                     |

<Tip>
  API Reference:

  * [Create source](/en/reference/matcher/create-source)
  * [Get source](/en/reference/matcher/retrieve-source)
  * [Update source](/en/reference/matcher/update-source)
  * [Archive source](/en/reference/matcher/archive-source)
  * [Restore source](/en/reference/matcher/restore-source)
</Tip>

## Source bindings

***

Bindings define how the binding scheduler can pull source data without a manual file upload. A **source binding** ties a source to the rail that supplies its transactions, plus a duration that determines when it is due. Exactly one rail is meaningful per binding `kind`:

* `file` — fetches files via a transport (populates `transportConfig`).
* `query` — pulls rows through a discovery-engine connection (populates `connectionId`; see [Discovery](/en/matcher/integrations/matcher-discovery)).

Bindings live under `/v1/contexts/{contextId}/sources/{sourceId}/bindings`.

<Note>
  A binding is dispatched only when the binding scheduler is enabled (it is disabled by default), the binding is enabled, and the binding is due. Creating or enabling a binding does not run it immediately.
</Note>

| Action         | Method & path                                                             |
| -------------- | ------------------------------------------------------------------------- |
| Create binding | `POST /v1/contexts/{contextId}/sources/{sourceId}/bindings`               |
| List bindings  | `GET /v1/contexts/{contextId}/sources/{sourceId}/bindings`                |
| Get binding    | `GET /v1/contexts/{contextId}/sources/{sourceId}/bindings/{bindingId}`    |
| Update binding | `PATCH /v1/contexts/{contextId}/sources/{sourceId}/bindings/{bindingId}`  |
| Delete binding | `DELETE /v1/contexts/{contextId}/sources/{sourceId}/bindings/{bindingId}` |

List returns **every** binding, enabled and disabled, so a disabled binding stays visible instead of silently vanishing.

### Create a query-rail binding

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts/{contextId}/sources/{sourceId}/bindings" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "kind": "query",
   "connectionId": "550e8400-e29b-41d4-a716-446655440000",
   "format": "br/cnab400/default",
   "scheduleSpec": "1h",
   "enabled": true
 }'
```

#### Fields

<ParamField path="kind" type="string" required>
  Rail the source is pulled on: `file` or `query` (required).
</ParamField>

<ParamField path="connectionId" type="string (UUID)">
  Query-rail discovery-engine connection. Required for `query`, rejected for `file`.
</ParamField>

<ParamField path="format" type="string">
  Declared format the binding produces (region/family-namespaced descriptor key, e.g. `br/cnab400/default`).
</ParamField>

<ParamField path="scheduleSpec" type="string">
  Go duration string the binding scheduler reads, such as `1h` or `30m`. Cron and `@every` syntax are invalid.
</ParamField>

<ParamField path="enabled" type="boolean">
  Whether the scheduler can dispatch the binding when it is due. Defaults to `true`; enabling it does not run it immediately.
</ParamField>

<Tip>
  API Reference:

  * [Create source binding](/en/reference/matcher/create-source-binding)
  * [List source bindings](/en/reference/matcher/list-source-bindings)
  * [Get source binding](/en/reference/matcher/get-source-binding)
  * [Update source binding](/en/reference/matcher/update-source-binding)
  * [Delete source binding](/en/reference/matcher/delete-source-binding)
</Tip>

## Managing contexts

***

As reconciliations evolve, you'll adjust a context's settings, pause it, retire it, or copy it. These lifecycle operations preserve history so you never lose an audit trail.

### Update a context

```bash cURL theme={null}
curl -X PATCH "https://api.matcher.example.com/v1/contexts/{contextId}" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Daily Bank Reconciliation - Updated",
   "interval": "weekly",
   "status": "PAUSED"
 }'
```

<Tip>
  API Reference: [Update context](/en/reference/matcher/update-context)
</Tip>

### Pause a context

To temporarily stop a context from being used in reconciliation runs, update its status to `PAUSED`:

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

Pausing a context:

* Prevents new match runs
* Preserves historical data
* Allows future reactivation by setting status back to `ACTIVE`

### Archive a context

Archiving is a reversible soft-delete. Instead of permanently removing a context, it moves the context to the `ARCHIVED` status, preserving its full history (sources, rules, match runs, and audit records) while excluding it from the default context listing.

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

Archiving a context:

* Sets the context status to `ARCHIVED`
* Preserves the complete history and audit trail
* Excludes the context from the default listing
* Can be reversed at any time with the [restore](#restore-a-context) endpoint

<Tip>
  API Reference: [Archive context](/en/reference/matcher/archive-context)
</Tip>

### Restore a context

Restoring reverses an archive, moving the context from `ARCHIVED` back to `DRAFT` so it can be reviewed and reconfigured before being reactivated.

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

Restoring a context:

* Sets the context status from `ARCHIVED` back to `DRAFT`
* Does **not** resume matching automatically—review and reactivate the context to run reconciliation again
* Returns `409 Conflict` if called on a context that is not archived

<Tip>
  API Reference: [Restore context](/en/reference/matcher/restore-context)
</Tip>

### Clone a context

To duplicate an existing context with its sources, rules, fee rules, and field maps, use the clone endpoint. This is useful for creating templates or replicating configurations across environments. Cloned fee rules keep referencing the same fee schedules as the source context; the fee schedules themselves are not copied.

```bash cURL theme={null}
curl -X POST "https://api.matcher.example.com/v1/contexts/{contextId}/clone" \
 -H "Authorization: Bearer $TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "name": "Q1 2025 Reconciliation (Copy)",
   "includeSources": true,
   "includeRules": true
 }'
```

The response reports how many sources, rules, fee rules, and field maps were copied. A successful clone is returned in `ACTIVE` status.

<Tip>
  API Reference: [Clone context](/en/reference/matcher/clone-context)
</Tip>

## Context lifecycle

***

A reconciliation context follows a well-defined lifecycle that controls when matching can run and how data is preserved.

* A context is first created in **Draft**, where sources and settings are configured.
* A context remains **Draft** until an explicit update sets it to `ACTIVE`. Activation validates the required sources on both `LEFT` and `RIGHT` sides, field mappings or CAMT options, match rules, and fee rules when fee normalization is enabled.
* An active context can be temporarily **Paused** to stop execution without affecting configuration or historical data.
* When a context is no longer needed, it can be **Archived** via the [archive](#archive-a-context) endpoint. Archiving is a reversible soft-delete: it moves the context to `ARCHIVED`, preserves the full history and audit records, and excludes it from the default listing. An archived context can be brought back to **Draft** at any time with the [restore](#restore-a-context) endpoint.

<Frame caption="Lifecycle of a Matcher context">
  <img src="https://mintcdn.com/lerian-49cb71fc/SEOef3JqTInYAAau/images/en/d2/matcher-context-lifecycle.svg?fit=max&auto=format&n=SEOef3JqTInYAAau&q=85&s=ec12c56f8493c36ff9b33c905569a633" alt="Matcher Context Lifecycle" width="465" height="880" data-path="images/en/d2/matcher-context-lifecycle.svg" />
</Frame>

This lifecycle ensures operational control, predictable execution, and full traceability across reconciliation periods.

## Best practices

***

<AccordionGroup>
  <Accordion title="Use descriptive names">
    Use explicit names that reflect accounts, systems, and purpose.
  </Accordion>

  <Accordion title="Start with conservative thresholds">
    Favor accuracy over automation initially. Adjust thresholds based on observed results.
  </Accordion>

  <Accordion title="Separate concerns">
    Use multiple contexts instead of a single broad reconciliation.
  </Accordion>

  <Accordion title="Flag regulatory sources">
    Always mark sources with compliance requirements.
  </Accordion>

  <Accordion title="Align timezones">
    Ensure source timezones reflect the original data feed.
  </Accordion>

  <Accordion title="Document sign conventions">
    Explicitly define debit and credit semantics for each source.
  </Accordion>
</AccordionGroup>

## Next steps

***

<Card title="Field mapping" icon="arrows-left-right" href="/en/matcher/configuration/matcher-field-mapping" horizontal>
  Define how source fields map to Matcher's schema.
</Card>

<Card title="Match rules" icon="scale-balanced" href="/en/matcher/configuration/matcher-match-rules" horizontal>
  Configure the rules that drive reconciliation.
</Card>
