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

# Simulation

> Dry-run a match rule against a context and preview fee calculations for a schedule — both read-only, so you can validate configuration before committing anything.

Matcher exposes two read-only simulation endpoints so you can answer "what would happen?" before you commit configuration: **match simulation** (will this rule actually match?) and **fee simulation** (what fees would this schedule charge?). Neither persists anything.

## Match simulation

***

Preview how a single rule — an existing configured rule (`ruleId`) **or** an inline candidate rule (`rule`) — would match a context's unmatched transactions, without committing anything.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/matching/simulate" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "contextId": "550e8400-e29b-41d4-a716-446655440000",
    "rule": {
      "type": "TOLERANCE",
      "config": { "matchAmount": true, "matchCurrency": true, "tolerance": 0.01 }
    },
    "sampleLimit": 25
  }'
```

Supply **exactly one** of:

* `ruleId` — preview an existing configured rule of the context.
* `rule` — preview an un-persisted candidate definition (`type` is one of `EXACT`, `TOLERANCE`, `DATE_LAG`, `FUZZY`, plus its `config`).

Supplying both, or neither, returns `400`. `sampleLimit` (1–200, default 25) caps the returned would-match pairs.

The response reports how many 1:1 groups the rule would form, a bounded sample of would-match pairs (each with a confidence score and per-component rationale), and the per-side unmatched counts:

```json theme={null}
{
  "ruleType": "TOLERANCE",
  "matchedGroups": 12,
  "unmatchedLeft": 3,
  "unmatchedRight": 5,
  "sampleTruncated": false,
  "sample": [
    {
      "left":  { "id": "...", "amount": "100.00", "currency": "BRL", "date": "2025-06-01T00:00:00Z" },
      "right": { "id": "...", "amount": "100.00", "currency": "BRL", "date": "2025-06-01T00:00:00Z" },
      "score": 90,
      "why": { "amountMatch": true, "currencyMatch": true, "dateMatch": true, "referenceScore": 0 },
      "amountDelta": "0.00",
      "dateDeltaDays": 0
    }
  ]
}
```

<Note>Scope: the simulation scores by the deterministic rule engine over the **raw** transaction amounts. It does **not** apply run-time fee normalization or the FX-variance band, and it previews only 1:1 pairwise grouping (no 1:N/N:M allocation). A pair that only matches after fee normalization, inside the FX band, or via allocation is not counted here.</Note>

## Fee simulation

***

Calculate fees for a given gross amount using a specific fee schedule. Use it to validate a schedule's rules before you attach it to a context.

```bash theme={null}
curl -X POST "https://api.matcher.example.com/v1/fee-schedules/{scheduleId}/simulate" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "grossAmount": "100.00", "currency": "USD" }'
```

The response returns the net amount, the total fee, and a per-item breakdown:

```json theme={null}
{
  "grossAmount": "100.00",
  "netAmount": "97.70",
  "totalFee": "2.30",
  "currency": "USD",
  "items": [
    { "name": "interchange", "fee": "1.50", "baseUsed": "100.00" }
  ]
}
```

<Note>Fee simulation has no transaction metadata, so expression-fee items that require a transaction identifier surface their missing-identifier error as a `4xx`. A missing schedule returns `404`.</Note>

## When to use each

***

| Use                                                         | When                                                                                                                                     |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Match simulation** (`/matching/simulate`)                 | You are authoring or reviewing a match rule and want to see how many transactions it would group, and which pairs, before committing it. |
| **Fee simulation** (`/fee-schedules/{scheduleId}/simulate`) | You are configuring a fee schedule and want to verify the net/fee breakdown it would produce for a representative gross amount.          |

Both are strictly read-only: they never persist a run, group, item, rule, or transaction, and the tenant is always taken from the JWT.

## Response codes

***

| Status | Meaning                                                                   |
| ------ | ------------------------------------------------------------------------- |
| `200`  | Simulation returned                                                       |
| `400`  | Invalid input (ambiguous/missing rule, invalid ids, invalid gross amount) |
| `404`  | Context, rule, or fee schedule not found                                  |
| `503`  | Match simulation not available                                            |
