---
id: CAP-ACC-REC-008
title: Prepare a payout explanation from matching evidence
feature: FEAT-ACC-REC-02
product_area: accounting
module: reconciliation
revision: 2
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes:
  - 'react-console acceptance inventory CAP-ACC-REC-004 (create, candidates, dismissals, notes and reads)'
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - >-
    services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§2: matching by evidence (suggested / all,
    claims, dismissals, releases))
  - 'services-accounting:docs/reconciliation/architecture.md#11.2 Tiers (Andrew''s Decision 1, 2026-10-16)'
  - 'services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D6 (architecture §3.4 U2, U3)'
  - >-
    services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§4: the architecture §6 invariants hold;
    INV-06, INV-13)
purpose: Preparers need a workspace that presents the financial effects likely to explain their deposits.
outcomes:
  - An active explanation owns each payout exclusively.
  - Candidate reasons support evidence-led selection.
  - Other draft holdings remain visible separately.
concepts:
  - CON-ACC-REC-003
  - CON-ACC-REC-002
  - CON-ACC-REC-001
actors:
  - ACT-ACC-017
  - ACT-ACC-018
  - ACT-ACC-007
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: accounting.reconciliation-batches.create
    where_checked: api
    scope: tenant
  - key: accounting.reconciliation-batches.read
    where_checked: api
    scope: tenant
  - key: accounting.reconciliation-batches.update
    where_checked: api
    scope: tenant
  - key: accounting.reconciliation-batches.update
    where_checked: console
    scope: tenant
rules:
  - id: BR-CAP-ACC-REC-008-01
    proved_by: [ATS-ACC-REC-008-01, TST-ACC-REC-027, TST-ACC-REC-069]
    statement: >-
      Creation links one to fifty nonvoided payouts from one merchant, rejects any already actively held
      payout and replays the same reconciliation under its request key.
    kind: validation
    enforced_at:
      - api
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#refuses
      payouts of two merchant accounts with 400;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#refuses
      a voided payout with 409 payout-voided naming it;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#refuses
      more than 50 payouts with 400;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#writes
      no batch for a refused create;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#answers
      the same Idempotency-Key and payouts with the same batch;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#refuses
      the same Idempotency-Key for other payouts with 409 idempotency-key-reused;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#refuses a
      create without the header with 400
    origin: >-
      services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§4: the architecture §6 invariants hold;
      INV-13, INV-19)
  - id: BR-CAP-ACC-REC-008-02
    proved_by: [ATS-ACC-REC-008-02, TST-ACC-REC-035, TST-ACC-REC-075]
    statement: >-
      Concurrent attempts to reconcile one payout produce one active holder, and the loser receives that
      reconciliation and its preparer.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/reconciliation-batches/claim-concurrency.integration.spec.js#refuses
      the second with 409 payout_held naming the first batch and its preparer;
      services-accounting:modules/reconciliation/tests/integration/services/reconciliation-batches/claim-concurrency.integration.spec.js#lets
      the first create succeed;
      services-accounting:modules/reconciliation/tests/integration/services/reconciliation-batches/claim-concurrency.integration.spec.js#leaves
      exactly one active link of the payout;
      services-accounting:modules/reconciliation/tests/integration/db/reconciliation-batch-payouts.table.integration.spec.js#refuses
      a second draft’s link of a payout another draft holds
    origin: >-
      services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§4: the architecture §6 invariants hold;
      INV-06)
  - id: BR-CAP-ACC-REC-008-03
    proved_by: [ATS-ACC-REC-002-09, ATS-ACC-REC-008-03, TST-ACC-REC-027, TST-ACC-REC-069]
    statement: >-
      A created reconciliation is open and numbered, retains its creator as preparer, links the payouts at
      their net amounts and starts with their negative total as its difference.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#writes
      an open draft batch numbered 10001, prepared by the caller, with the payouts’ total;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#links
      each payout at its net amount, payout number order;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#records
      batch.created with its number, payouts, total and version and the idempotency key;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#numbers
      the tenant’s next batch 10002;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#creates a draft
      batch over the payout, its difference minus the payout
    origin: >-
      services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D6 (architecture §3.4 U7: difference is net
      reconciled minus payout)
  - id: BR-CAP-ACC-REC-008-04
    proved_by: [ATS-ACC-REC-005-13, ATS-ACC-REC-008-04, ATS-ACC-REC-008-12, ATS-ACC-REC-013-10, TST-ACC-REC-027, TST-ACC-REC-062]
    statement: >-
      Matching considers unresolved eligible items in the reconciliation’s unit, merchant and currency,
      separates items held by another open draft and hides conflicting processor payout references unless
      searched.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#answers
      the item another open batch claims only in held, with its holder;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#leaves
      out an item naming a different payout when nobody searches;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#shows
      an item naming a different payout to a search, tier 5 with the conflict;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#never
      answers a withdrawn item or one not yet eligible, though each matches the payout;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#never
      answers another merchant account’s or another unit’s items, though each names the payout;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#answers the
      captures RB-10001 holds apart, with their holder
    origin: 'services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D6 (architecture §3.4 U2)'
  - id: BR-CAP-ACC-REC-008-05
    proved_by: [ATS-ACC-REC-008-05, ATS-ACC-REC-008-11, TST-ACC-REC-005, TST-ACC-REC-028, TST-ACC-REC-086]
    statement: >-
      Candidate strength follows payout reference, processor line, authoritative settlement grouping,
      expected-day correlation since the prior deposit or a five-business-day fallback, then weak manual
      suggestion, with reasons retained.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      expected after the previous deposit and before this one;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate the
      processor reports paid in this payout;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      settled in a processor batch with an item claimed by payout reference;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      expected 4 business days before the deposit, with no previous payout;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      expected on the sixth business day before the deposit, with no previous payout;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate the
      same whatever amount it carries;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-scenario.e2e.spec.js#step 4:
      suggests by date alone, never a combination of amounts that adds up to the deposit;
      react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0595.spec.ts#ACT-ACC-0595
    origin: 'services-accounting:docs/reconciliation/architecture.md#11.2 Tiers (Andrew''s Decision 1, 2026-10-16)'
  - id: BR-CAP-ACC-REC-008-06
    proved_by: [ATS-ACC-REC-008-05, ATS-ACC-REC-008-11, TST-ACC-REC-005, TST-ACC-REC-028, TST-ACC-REC-086]
    statement: >-
      Matching does not seek combinations of amounts that equal the deposit; amounts serve display and search
      only.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate the
      same whatever amount it carries;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate the
      processor reports paid in this payout;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      settled in a processor batch with an item claimed by payout reference;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      expected after the previous deposit and before this one;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      expected 4 business days before the deposit, with no previous payout;
      services-accounting:modules/reconciliation/tests/unit/rules/match-ranking.spec.js#ranks a candidate
      expected on the sixth business day before the deposit, with no previous payout;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-scenario.e2e.spec.js#step 4:
      suggests by date alone, never a combination of amounts that adds up to the deposit;
      react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0595.spec.ts#ACT-ACC-0595
    origin: 'services-accounting:docs/reconciliation/brief.md#Matching engine (Andrew’s product brief, 2026-10-15)'
  - id: BR-CAP-ACC-REC-008-07
    proved_by: [ATS-ACC-REC-008-06, TST-ACC-REC-027, TST-ACC-REC-062]
    statement: >-
      Suggested results include undismissed ranks one through four, while all results add weaker and dismissed
      rows; the default fourteen-day-before and three-day-after window extends for an older previous deposit
      and supports explicit widening.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#answers
      tiers 1 to 4 not dismissed, each candidate whole, the held item apart, with the default window;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#answers
      every row of the guard, tier 5 and the dismissed flagged, each candidate whole;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#leaves
      out items expected outside the default window;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#finds
      an item after the window when `to` widens it;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#answers the
      default window, 14 days before the payout to 3 days after;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-candidates.queries.integration.spec.js#answers
      the default window from the day after the previous deposit
    origin: >-
      services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (plan approved 2026-10-22 10:40 ET; §2
      scope)
  - id: BR-CAP-ACC-REC-008-08
    proved_by: [ATS-ACC-REC-008-07, ATS-ACC-REC-008-11, ATS-ACC-REC-008-14, TST-ACC-REC-005, TST-ACC-REC-037, TST-ACC-REC-063]
    statement: >-
      Dismissal belongs to this reconciliation, optionally records a reason, leaves version and totals alone,
      is repeat-safe and can be undone while open.
    kind: policy
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-dismissals.integration.spec.js#leaves
      the batch’s version and totals as they were;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-dismissals.integration.spec.js#answers
      the dismissal as written;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-dismissals.integration.spec.js#answers
      a second dismissal of the item with the first;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-dismissals.integration.spec.js#records
      no event for the second dismissal;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-dismissals.integration.spec.js#refuses
      another merchant account’s item with 400;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-dismissals.integration.spec.js#refuses
      a dismissal in a batch that is not open with 409 batch-not-open;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-dismissals.integration.spec.js#refuses
      a second undo with 404;
      services-accounting:modules/reconciliation/tests/integration/db/reconciliation-dismissals.table.integration.spec.js#refuses
      deleting the dismissal of a finalized batch (RHF30);
      react-console:acceptance/accounting/playwright/journeys/reconciliation-close/ACT-ACC-0595.spec.ts#ACT-ACC-0595
    origin: >-
      services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (plan approved 2026-10-22 10:40 ET; §2
      scope)
  - id: BR-CAP-ACC-REC-008-09
    proved_by: [ATS-ACC-REC-008-08, TST-ACC-REC-069]
    statement: >-
      Open reconciliation notes replace or clear up to four thousand characters using the saved version;
      sealed reconciliations reject that change.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#refuses
      notes in a batch that is not open with 409 batch-not-open;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#writes
      the notes one version on, by the caller;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#records
      batch.notes-updated with the versions;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#refuses
      notes at a version that is not the batch’s with 409 StaleObject;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.integration.spec.js#clears
      the notes with null
    origin: none
  - id: BR-CAP-ACC-REC-008-10
    proved_by: [ATS-ACC-REC-008-09, ATS-ACC-REC-008-13, TST-ACC-REC-027, TST-ACC-REC-070]
    statement: >-
      The workspace separates manual entries from matched items grouped by operational batch and provides
      chronological activity.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.queries.integration.spec.js#groups
      the active claims by operational batch with their count and amount, the claims without one last;
      services-accounting:modules/reconciliation/tests/integration/services/persistence/reconciliation-workspaces.queries.integration.spec.js#answers
      every event oldest first with every mapped property, and no cursor after the last;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#lists the
      operational batch the remaining claim came from;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#lists every
      event of the batch, oldest first
    origin: >-
      services-accounting:docs/reconciliation/brief.md#Three core concepts (Andrew’s product brief,
      2026-10-15)
  - id: BR-CAP-ACC-REC-008-11
    proved_by: [ATS-ACC-REC-008-10, TST-ACC-REC-027, TST-ACC-REC-096]
    statement: >-
      Create, read and update permissions separately govern opening, inspection and notes or dismissal, with
      no write actions for readers and no cross-workspace reads.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#refuses the
      reader a create with 403;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#lets a
      principal with the read key alone read the batch;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#offers the
      reader no action;
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-matching.e2e.spec.js#answers 404 for
      tenant A’s batch in tenant B;
      services-accounting:tests/unit/reconciliation-matching-routes.spec.ts#serves the create under
      accounting.reconciliation-batches.create;
      services-accounting:tests/unit/reconciliation-matching-routes.spec.ts#serves every command on an open
      batch under accounting.reconciliation-batches.update;
      services-accounting:tests/unit/reconciliation-matching-routes.spec.ts#serves the candidates, the source
      batches and the history under accounting.reconciliation-batches.read
    origin: 'services-accounting:docs/milestones/plans/ACCT-M8-plan.md#D10 (§2: permissions)'
  - id: BR-CAP-ACC-REC-008-12
    proved_by: []
    statement: >-
      The console begins reconciliation from a payout and retrieves the all-candidates view before applying
      suggestion filters locally.
    kind: policy
    enforced_at:
      - console
    must_prove: false
    provenance: observed
    source: 'react-console:lib/accounting/reconciliation/client.ts:candidates'
    origin: none
scenarios:
  - id: SC-CAP-ACC-REC-008-01
    given: Forty-two captures and a refund fall within the fallback window before the sample deposit.
    when: Inspect suggested candidates.
    then: Their expected-day evidence places them in the correlation suggestions.
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-scenario.e2e.spec.js#step 4:
      suggests the 42 captures and the refund tier 4, within 5 business days before the deposit (no previous
      payout)
  - id: SC-CAP-ACC-REC-008-02
    given: The gift is expected after the deposit day.
    when: Inspect all candidates.
    then: It remains a weak candidate with the after-deposit reason rather than a suggestion.
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/e2e/reconciliation-scenario.e2e.spec.js#step 4: never
      suggests the $500 gift, expected after the deposit, and says so among all candidates
edge_cases:
  - id: SC-CAP-ACC-REC-008-03
    given: Two preparers select the same payout concurrently.
    when: Both create an explanation.
    then: One wins and the refusal identifies its reconciliation and preparer.
    provenance: test
    source: >-
      services-accounting:modules/reconciliation/tests/integration/services/reconciliation-batches/claim-concurrency.integration.spec.js#refuses
      the second with 409 payout_held naming the first batch and its preparer
constraints: []
depends_on:
  - CAP-ACC-REC-001
  - CAP-ACC-REC-005
related:
  - CAP-ACC-REC-009
  - CAP-ACC-REC-010
  - CAP-ACC-REC-012
journeys:
  - JNY-ACC-REC-001
open_questions: []
evidence:
  - >-
    Examined supporting service material: matching.routes.ts (createReconciliationBatch,
    getReconciliationBatch, updateReconciliationBatchNotes, listReconciliationCandidates,
    dismissReconciliationItem, undismissReconciliationItem, listReconciliationSourceBatches,
    listReconciliationBatchEvents), reconciliation.routes.ts (listReconciliationBatches), matching.schemas.ts,
    services/persistence/reconciliation-workspaces.ts, reconciliation-candidates.ts,
    reconciliation-dismissals.ts, rules/match-ranking.ts, reconciliation-batches/batch-views.ts;
    db/reconciliation-batches.table.ts, reconciliation-batch-links.table.ts (payout links, claims,
    dismissals); tests e2e/reconciliation-matching.e2e.spec.js, reconciliation-lists.e2e.spec.js, integration
    reconciliation-workspaces*, reconciliation-candidates.queries, reconciliation-dismissals,
    claim-concurrency, unit/rules/match-ranking.spec.js; docs/reconciliation/architecture.md §11.
  - >-
    Examined supporting console material: components/accounting/reconciliation/workspace/workspace.tsx,
    matching.tsx, original-batches.tsx; lib/accounting/reconciliation/client.ts, adapter.ts; acceptance
    journey ACT-ACC-0595.
controls: [TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002]
exercised_by: [FAS-ACC-REC-02-01, FAS-ACC-REC-02-02, FAS-ACC-REC-02-03, FAS-ACC-REC-02-04, FAS-ACC-REC-02-05]
suites: [TST-ACC-REC-005, TST-ACC-REC-027, TST-ACC-REC-028, TST-ACC-REC-035, TST-ACC-REC-037, TST-ACC-REC-062, TST-ACC-REC-063, TST-ACC-REC-069, TST-ACC-REC-070, TST-ACC-REC-075, TST-ACC-REC-086, TST-ACC-REC-096]
---

# Prepare a payout explanation from matching evidence

## Purpose

Preparers need a workspace that presents the financial effects likely to explain their deposits.

## How It Works

A preparer opens an explanation over the selected payouts. Rhythm presents candidates with reasons and separates money another draft holds. The preparer examines strong evidence before using weaker date suggestions. Notes and dismissals help organize review without claiming that the deposit is complete. Competing ownership or invalid payout context stops draft creation.

## Relationships

Payouts anchor the explanation, settlement records supply candidates and claims or manual entries complete preparation.
