# Reconciliation tools

> MCP tools for Reconciliation: reconciliation_connections_list, reconciliation_items_get, reconciliation_items_ignore, reconciliation_items_list, reconciliation_items_resolve, reconciliation_runs_create.

- `reconciliation_connections_list`: List the processor connections' reconciliation
- `reconciliation_items_get`: Get a reconciliation item
- `reconciliation_items_ignore`: Ignore a reconciliation item
- `reconciliation_items_list`: List reconciliation items
- `reconciliation_items_resolve`: Resolve a reconciliation item
- `reconciliation_runs_create`: Reconcile a processor connection now

## `reconciliation_connections_list`

**List the processor connections' reconciliation.** Operation [`reconciliation.connections.list`](https://ownrecord.io/docs/reference/reconciliation-connections-list.md) · Legal entity level · permission `ledger:read` · risk tier `read` · since M8

Lists the legal entity's processor connections in the mode of the request with where their reconciliation
stands: the cursor (the latest balance transaction read), the last run (scheduled daily or asked for, what it
read, matched, posted and queued, or why it failed), a run asked for and not finished yet, and the open items.

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument    | Type         | Required | Description                                                                                                                                       |
| ----------- | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entity_id` | ID (`ent_…`) | no       | The legal entity to act on (ent\_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |

- **Legal entity:** pass `entity_id` with an organization key; entity and brand keys act on their own entity.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no legal entity (an org key without `Ownrecord-Entity`, or a brand key: reconciliation belongs to the entity).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't read this entity's ledger (`ledger:read`; brand-scoped members never see it).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live reconciliation.

### Example

**One Stripe connection, reconciled this morning**

Arguments:

```json
{
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy"
}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "object": "reconciliation_connection",
      "processorConnectionId": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
      "livemode": false,
      "processor": "stripe",
      "label": "Stripe (test)",
      "status": "active",
      "cursor": "2026-11-05T00:10:00.000Z",
      "lastRun": {
        "trigger": "schedule",
        "startedAt": "2026-11-05T04:00:00.000Z",
        "finishedAt": "2026-11-05T04:00:12.000Z",
        "status": "succeeded",
        "readFrom": "2026-11-03T23:59:00.000Z",
        "counts": {
          "read": 42,
          "recorded": 40,
          "matched": 39,
          "opened": 1,
          "posted": 35,
          "rechecked": 0,
          "bankConfirmed": 1
        },
        "error": null
      },
      "lastSucceededAt": "2026-11-05T04:00:12.000Z",
      "runRequestedAt": null,
      "openItems": 1
    }
  ]
}
```

## `reconciliation_items_get`

**Get a reconciliation item.** Operation [`reconciliation.items.get`](https://ownrecord.io/docs/reference/reconciliation-items-get.md) · Legal entity level · permission `ledger:read` · risk tier `read` · since M8

Returns one reconciliation item: what the processor (or the bank statement) reported, what it matched in
Ownrecord (payment, refund or dispute), the fee and payout postings reconciliation made for it, and for an open
item why it couldn't be matched. A resolved or ignored item carries the person's note.

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument    | Type         | Required | Description                                                                                                                                            |
| ----------- | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`        | string       | yes      | The item's ID: `{processor connection}:{balance transaction or payout ID}` for processor items, the bank statement line's ID (`bsl_…`) for bank items. |
| `entity_id` | ID (`ent_…`) | no       | The legal entity to act on (ent\_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity.      |

- **Legal entity:** pass `entity_id` with an organization key; entity and brand keys act on their own entity.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): `id` isn't a reconciliation item ID.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): This entity has no such item in this mode.
- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no legal entity (an org key without `Ownrecord-Entity`, or a brand key: reconciliation belongs to the entity).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't read this entity's ledger (`ledger:read`; brand-scoped members never see it).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live reconciliation.

### Example

**A charge matched to its payment, its fee posted**

Arguments:

```json
{
  "id": "pcon_01m4vyt4mxe0s9zzk90373z6p6:txn_3QCharge1",
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy"
}
```

Result `output`:

```json
{
  "object": "reconciliation_item",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "processorConnectionId": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
  "processor": "stripe",
  "availableOn": "2026-11-06T00:00:00.000Z",
  "match": {
    "paymentId": "pay_01m4tx5nj8emwbyf7y9vcf49aa",
    "refundId": null,
    "disputeId": null,
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47z0"
  },
  "ledgerTxnIds": ["txn_01m4tx5nj8emwbyf7y9vcf49ab"],
  "payout": null,
  "bankLine": null,
  "resolution": null,
  "lastCheckedAt": "2026-11-05T04:00:12.000Z",
  "createdAt": "2026-11-05T04:00:12.000Z",
  "updatedAt": "2026-11-05T04:00:12.000Z",
  "version": 1,
  "id": "pcon_01m4vyt4mxe0s9zzk90373z6p6:txn_3QCharge1",
  "source": "processor",
  "kind": "charge",
  "status": "matched",
  "reason": null,
  "reference": "txn_3QCharge1",
  "balanceTransactionRefs": ["txn_3QCharge1"],
  "sourceRef": "ch_3QCharge1",
  "amount": {
    "amount": "125000000",
    "currency": "EUR"
  },
  "fee": {
    "amount": "2000000",
    "currency": "EUR"
  },
  "net": {
    "amount": "123000000",
    "currency": "EUR"
  },
  "occurredAt": "2026-11-04T10:02:00.000Z"
}
```

## `reconciliation_items_ignore`

**Ignore a reconciliation item.** Operation [`reconciliation.items.ignore`](https://ownrecord.io/docs/reference/reconciliation-items-ignore.md) · Legal entity level · permission `ledger:write` · risk tier `write` · since M8

Takes an open reconciliation item out of the queue because nothing needs to be done (for example a transfer
between the entity's own accounts), with a note. Nothing is posted. A bank item's line is ignored in its
statement too. When a processor connection has no open items left, its RECON_UNMATCHED alert is resolved.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | string       | yes      | The item's ID: `{processor connection}:{balance transaction or payout ID}` for processor items, the bank statement line's ID (`bsl_…`) for bank items.                                                   |
| `note`            | string       | yes      | Why the item is accounted for, or why nothing is to be done (kept with the item and in the audit log). (1–1000 characters)                                                                               |
| `expectedVersion` | integer      | no       | (1–9007199254740991)                                                                                                                                                                                     |
| `entity_id`       | ID (`ent_…`) | no       | The legal entity to act on (ent\_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity.                                                        |
| `idempotency_key` | string       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Legal entity:** pass `entity_id` with an organization key; entity and brand keys act on their own entity.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): The note is empty or too long.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): This entity has no such item in this mode.
- [`reconciliation_item_closed`](https://ownrecord.io/docs/reference/errors.md#reconciliation_item_closed): The item is resolved or ignored already (`details.status`).
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The item changed since you read it (`expectedVersion`), or at the same moment.
- [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused): The idempotency key was used before for another request.
- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no legal entity (an org key without `Ownrecord-Entity`, or a brand key: reconciliation belongs to the entity).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't work this entity's reconciliation (`ledger:write`: finance, owners and admins).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live reconciliation.

### Example

**A transfer from the entity's savings account**

Arguments:

```json
{
  "id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
  "note": "Own transfer from savings",
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "reconciliation_item",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "processorConnectionId": null,
  "processor": null,
  "availableOn": null,
  "match": {
    "paymentId": null,
    "refundId": null,
    "disputeId": null,
    "brandId": null
  },
  "ledgerTxnIds": [],
  "payout": null,
  "bankLine": {
    "lineId": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
    "importId": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
    "bookingDate": "2026-11-04",
    "counterparty": "Acme d.o.o.",
    "candidatePayoutItemIds": []
  },
  "resolution": {
    "action": "ignored",
    "note": "Own transfer from savings",
    "by": {
      "type": "user",
      "id": "usr_01m4tx5nj8emwbyf7y9vcf47zk"
    },
    "at": "2026-11-05T10:00:00.000Z",
    "payoutItemId": null
  },
  "lastCheckedAt": "2026-11-05T04:00:12.000Z",
  "createdAt": "2026-11-05T04:00:12.000Z",
  "updatedAt": "2026-11-05T10:00:00.000Z",
  "version": 2,
  "id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
  "source": "bank",
  "kind": "bank_line",
  "status": "ignored",
  "reason": null,
  "reference": "Transfer from savings",
  "balanceTransactionRefs": [],
  "sourceRef": null,
  "amount": {
    "amount": "5000000000",
    "currency": "EUR"
  },
  "fee": null,
  "net": null,
  "occurredAt": "2026-11-04T00:00:00.000Z"
}
```

## `reconciliation_items_list`

**List reconciliation items.** Operation [`reconciliation.items.list`](https://ownrecord.io/docs/reference/reconciliation-items-list.md) · Legal entity level · permission `ledger:read` · risk tier `read` · since M8

Lists the legal entity's reconciliation items in the mode of the request, newest first. Every processor balance
transaction the daily reconciliation read is an item (payouts are one item each), and so is every imported bank
statement line that paid no invoice and confirmed no payout.

The **queue** is `status=open`: what Ownrecord couldn't match, with `reason` (e.g. `payment_unknown`: a charge no
payment of the connection has; `unsupported_type`: an adjustment; `no_match`: a bank line). Resolve each with
`reconciliation.items.resolve` or `.ignore`. The **payouts** are `kind=payout`, with their status and the bank
line that confirmed them. Filter by `source`, `kind`, `status` (one or several, comma-separated) and
`processorConnectionId`; paginate with `limit` (1–100, default 10) and `starting_after`.

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument                | Type                                                                                               | Required | Description                                                                                                                                       |
| ----------------------- | -------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`                | array of one of `open`, `matched`, `ignored`                                                       | no       | `open` (the queue), `matched`, `ignored`; one or several. (1–3 items)                                                                             |
| `kind`                  | array of one of `charge`, `refund`, `dispute`, `fee`, `payout`, `adjustment`, `other`, `bank_line` | no       | E.g. `payout` for the payouts; one or several. (1–8 items)                                                                                        |
| `source`                | one of `processor`, `bank`                                                                         | no       | –                                                                                                                                                 |
| `processorConnectionId` | ID (`pcon_…`)                                                                                      | no       | –                                                                                                                                                 |
| `limit`                 | integer                                                                                            | no       | (1–100)                                                                                                                                           |
| `starting_after`        | string                                                                                             | no       | The `next_cursor` of the previous page.                                                                                                           |
| `entity_id`             | ID (`ent_…`)                                                                                       | no       | The legal entity to act on (ent\_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |

- **Legal entity:** pass `entity_id` with an organization key; entity and brand keys act on their own entity.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A filter or pagination value is invalid, or `starting_after` is no item of this entity.
- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no legal entity (an org key without `Ownrecord-Entity`, or a brand key: reconciliation belongs to the entity).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't read this entity's ledger (`ledger:read`; brand-scoped members never see it).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live reconciliation.

### Examples

**The queue**

Arguments:

```json
{
  "status": ["open"],
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy"
}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "object": "reconciliation_item",
      "livemode": false,
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
      "processorConnectionId": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
      "processor": "stripe",
      "availableOn": null,
      "match": {
        "paymentId": null,
        "refundId": null,
        "disputeId": null,
        "brandId": null
      },
      "ledgerTxnIds": [],
      "payout": null,
      "bankLine": null,
      "resolution": null,
      "lastCheckedAt": "2026-11-05T04:00:12.000Z",
      "createdAt": "2026-11-05T04:00:12.000Z",
      "updatedAt": "2026-11-05T04:00:12.000Z",
      "version": 1,
      "id": "pcon_01m4vyt4mxe0s9zzk90373z6p6:txn_3QAdjustment1",
      "source": "processor",
      "kind": "adjustment",
      "status": "open",
      "reason": "unsupported_type",
      "reference": "txn_3QAdjustment1",
      "balanceTransactionRefs": ["txn_3QAdjustment1"],
      "sourceRef": null,
      "amount": {
        "amount": "-1000000",
        "currency": "EUR"
      },
      "fee": {
        "amount": "0",
        "currency": "EUR"
      },
      "net": {
        "amount": "-1000000",
        "currency": "EUR"
      },
      "occurredAt": "2026-11-04T15:20:00.000Z"
    },
    {
      "object": "reconciliation_item",
      "livemode": false,
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
      "processorConnectionId": null,
      "processor": null,
      "availableOn": null,
      "match": {
        "paymentId": null,
        "refundId": null,
        "disputeId": null,
        "brandId": null
      },
      "ledgerTxnIds": [],
      "payout": null,
      "bankLine": {
        "lineId": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
        "importId": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
        "bookingDate": "2026-11-04",
        "counterparty": "Acme d.o.o.",
        "candidatePayoutItemIds": []
      },
      "resolution": null,
      "lastCheckedAt": "2026-11-05T04:00:12.000Z",
      "createdAt": "2026-11-05T04:00:12.000Z",
      "updatedAt": "2026-11-05T04:00:12.000Z",
      "version": 1,
      "id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
      "source": "bank",
      "kind": "bank_line",
      "status": "open",
      "reason": "no_match",
      "reference": "Transfer from savings",
      "balanceTransactionRefs": [],
      "sourceRef": null,
      "amount": {
        "amount": "5000000000",
        "currency": "EUR"
      },
      "fee": null,
      "net": null,
      "occurredAt": "2026-11-04T00:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

**The payouts**

Arguments:

```json
{
  "kind": ["payout"],
  "limit": 1,
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy"
}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "object": "reconciliation_item",
      "livemode": false,
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
      "processorConnectionId": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
      "processor": "stripe",
      "availableOn": "2026-11-07T00:00:00.000Z",
      "match": {
        "paymentId": null,
        "refundId": null,
        "disputeId": null,
        "brandId": null
      },
      "ledgerTxnIds": ["txn_01m4tx5nj8emwbyf7y9vcf49ac"],
      "payout": {
        "ref": "po_1QPayout1",
        "status": "paid",
        "arrivalOn": "2026-11-07",
        "bankLineId": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
        "confirmedAt": "2026-11-08T09:00:00.000Z",
        "confirmedBy": "automatic"
      },
      "bankLine": null,
      "resolution": null,
      "lastCheckedAt": "2026-11-05T04:00:12.000Z",
      "createdAt": "2026-11-05T04:00:12.000Z",
      "updatedAt": "2026-11-05T04:00:12.000Z",
      "version": 1,
      "id": "pcon_01m4vyt4mxe0s9zzk90373z6p6:po_1QPayout1",
      "source": "processor",
      "kind": "payout",
      "status": "matched",
      "reason": null,
      "reference": "po_1QPayout1",
      "balanceTransactionRefs": ["txn_3QPayout1"],
      "sourceRef": "po_1QPayout1",
      "amount": {
        "amount": "-122000000",
        "currency": "EUR"
      },
      "fee": {
        "amount": "0",
        "currency": "EUR"
      },
      "net": {
        "amount": "-122000000",
        "currency": "EUR"
      },
      "occurredAt": "2026-11-05T00:10:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## `reconciliation_items_resolve`

**Resolve a reconciliation item.** Operation [`reconciliation.items.resolve`](https://ownrecord.io/docs/reference/reconciliation-items-resolve.md) · Legal entity level · permission `ledger:write` · risk tier `write` · since M8

Marks an open reconciliation item as accounted for, with a note saying how (for example the ledger adjustment
you booked for a processor correction). Nothing is posted by this call: corrections are manual ledger
adjustments (`ledger.adjustments.create`).

For a bank item (an imported statement line), name the payout the line confirms with `payoutItemId` (a
`kind: payout` item for exactly the line's amount): the line becomes matched to the payout, whose posting
(`Dr bank / Cr processor_clearing`) is already in the ledger. Without it, the line is also taken out of its
statement's review queue (ignored there, with your note).

When a processor connection has no open items left, its RECON_UNMATCHED alert is resolved.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | string       | yes      | The item's ID: `{processor connection}:{balance transaction or payout ID}` for processor items, the bank statement line's ID (`bsl_…`) for bank items.                                                   |
| `note`            | string       | yes      | Why the item is accounted for, or why nothing is to be done (kept with the item and in the audit log). (1–1000 characters)                                                                               |
| `payoutItemId`    | string       | no       | Bank items only: the payout item (`kind: payout`) the line confirms, for exactly its amount.                                                                                                             |
| `expectedVersion` | integer      | no       | The item's `version` you read (a guard against a concurrent change). (1–9007199254740991)                                                                                                                |
| `entity_id`       | ID (`ent_…`) | no       | The legal entity to act on (ent\_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity.                                                        |
| `idempotency_key` | string       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Legal entity:** pass `entity_id` with an organization key; entity and brand keys act on their own entity.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): The note is empty or too long, or `payoutItemId` was given for a processor item.
- [`reconciliation_payout_mismatch`](https://ownrecord.io/docs/reference/errors.md#reconciliation_payout_mismatch): `payoutItemId` isn't a payout of this entity, failed, is confirmed by another line, or has another amount or currency than the line.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): This entity has no such item in this mode.
- [`reconciliation_item_closed`](https://ownrecord.io/docs/reference/errors.md#reconciliation_item_closed): The item is resolved or ignored already (`details.status`).
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The item changed since you read it (`expectedVersion`), or at the same moment.
- [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused): The idempotency key was used before for another request.
- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no legal entity (an org key without `Ownrecord-Entity`, or a brand key: reconciliation belongs to the entity).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't work this entity's reconciliation (`ledger:write`: finance, owners and admins).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live reconciliation.

### Examples

**A processor correction booked by hand**

Arguments:

```json
{
  "id": "pcon_01m4vyt4mxe0s9zzk90373z6p6:txn_3QAdjustment1",
  "note": "Network cost correction, booked with adjustment txn_01m4…",
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "reconciliation_item",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "processorConnectionId": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
  "processor": "stripe",
  "availableOn": null,
  "match": {
    "paymentId": null,
    "refundId": null,
    "disputeId": null,
    "brandId": null
  },
  "ledgerTxnIds": [],
  "payout": null,
  "bankLine": null,
  "resolution": {
    "action": "resolved",
    "note": "Network cost correction, booked with adjustment txn_01m4…",
    "by": {
      "type": "user",
      "id": "usr_01m4tx5nj8emwbyf7y9vcf47zk"
    },
    "at": "2026-11-05T10:00:00.000Z",
    "payoutItemId": null
  },
  "lastCheckedAt": "2026-11-05T04:00:12.000Z",
  "createdAt": "2026-11-05T04:00:12.000Z",
  "updatedAt": "2026-11-05T10:00:00.000Z",
  "version": 2,
  "id": "pcon_01m4vyt4mxe0s9zzk90373z6p6:txn_3QAdjustment1",
  "source": "processor",
  "kind": "adjustment",
  "status": "matched",
  "reason": null,
  "reference": "txn_3QAdjustment1",
  "balanceTransactionRefs": ["txn_3QAdjustment1"],
  "sourceRef": null,
  "amount": {
    "amount": "-1000000",
    "currency": "EUR"
  },
  "fee": {
    "amount": "0",
    "currency": "EUR"
  },
  "net": {
    "amount": "-1000000",
    "currency": "EUR"
  },
  "occurredAt": "2026-11-04T15:20:00.000Z"
}
```

**A bank line that confirms a payout**

Arguments:

```json
{
  "id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
  "note": "Stripe payout, bank booked it a week late",
  "payoutItemId": "pcon_01m4vyt4mxe0s9zzk90373z6p6:po_1QPayout1",
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "reconciliation_item",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "processorConnectionId": null,
  "processor": null,
  "availableOn": null,
  "match": {
    "paymentId": null,
    "refundId": null,
    "disputeId": null,
    "brandId": null
  },
  "ledgerTxnIds": [],
  "payout": null,
  "bankLine": {
    "lineId": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
    "importId": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
    "bookingDate": "2026-11-04",
    "counterparty": "Acme d.o.o.",
    "candidatePayoutItemIds": []
  },
  "resolution": {
    "action": "resolved",
    "note": "Stripe payout, bank booked it a week late",
    "by": {
      "type": "user",
      "id": "usr_01m4tx5nj8emwbyf7y9vcf47zk"
    },
    "at": "2026-11-05T10:00:00.000Z",
    "payoutItemId": "pcon_01m4vyt4mxe0s9zzk90373z6p6:po_1QPayout1"
  },
  "lastCheckedAt": "2026-11-05T04:00:12.000Z",
  "createdAt": "2026-11-05T04:00:12.000Z",
  "updatedAt": "2026-11-05T10:00:00.000Z",
  "version": 2,
  "id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
  "source": "bank",
  "kind": "bank_line",
  "status": "matched",
  "reason": null,
  "reference": "Transfer from savings",
  "balanceTransactionRefs": [],
  "sourceRef": null,
  "amount": {
    "amount": "5000000000",
    "currency": "EUR"
  },
  "fee": null,
  "net": null,
  "occurredAt": "2026-11-04T00:00:00.000Z"
}
```

## `reconciliation_runs_create`

**Reconcile a processor connection now.** Operation [`reconciliation.runs.create`](https://ownrecord.io/docs/reference/reconciliation-runs-create.md) · Legal entity level · permission `ledger:write` · risk tier `write` · since M8

Asks for a reconciliation run of one processor connection now, besides the daily one. The run happens in the
background within a minute (`runRequestedAt` is set until it finishes): it reads the connection's balance
transactions since its cursor, matches them to payments, refunds and disputes, posts the processor fees and
payouts not posted yet (each once), puts what doesn't match in the queue and raises RECON_UNMATCHED when it
queued something new. Poll `reconciliation.connections.list` for the result (`lastRun`). Asking again while a
run is pending runs it again; that is harmless.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument                | Type          | Required | Description                                                                                                                                                                                              |
| ----------------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `processorConnectionId` | ID (`pcon_…`) | yes      | The connection to reconcile now (`pcon_…`).                                                                                                                                                              |
| `entity_id`             | ID (`ent_…`)  | no       | The legal entity to act on (ent\_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity.                                                        |
| `idempotency_key`       | string        | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`               | boolean       | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Legal entity:** pass `entity_id` with an organization key; entity and brand keys act on their own entity.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): `processorConnectionId` isn't a processor connection ID.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): This entity has no such processor connection in this mode.
- [`reconciliation_connection_unsupported`](https://ownrecord.io/docs/reference/errors.md#reconciliation_connection_unsupported): The connection is disconnected: its balance transactions can't be read any more.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): Another run was asked for at the same moment; retry.
- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no legal entity (an org key without `Ownrecord-Entity`, or a brand key: reconciliation belongs to the entity).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't work this entity's reconciliation (`ledger:write`: finance, owners and admins).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live reconciliation.

### Example

**Reconcile the Stripe connection now**

Arguments:

```json
{
  "processorConnectionId": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
  "entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "object": "reconciliation_connection",
  "processorConnectionId": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
  "livemode": false,
  "processor": "stripe",
  "label": "Stripe (test)",
  "status": "active",
  "cursor": "2026-11-05T00:10:00.000Z",
  "lastRun": {
    "trigger": "schedule",
    "startedAt": "2026-11-05T04:00:00.000Z",
    "finishedAt": "2026-11-05T04:00:12.000Z",
    "status": "succeeded",
    "readFrom": "2026-11-03T23:59:00.000Z",
    "counts": {
      "read": 42,
      "recorded": 40,
      "matched": 39,
      "opened": 1,
      "posted": 35,
      "rechecked": 0,
      "bankConfirmed": 1
    },
    "error": null
  },
  "lastSucceededAt": "2026-11-05T04:00:12.000Z",
  "runRequestedAt": "2026-11-05T10:00:00.000Z",
  "openItems": 1
}
```
