Reconciliation connects validated receipts to the intended invoices, then compares fulfilment and settlement records. Store each receipt once, apply an explicit matching policy and keep exceptions visible. A changing wallet balance cannot replace this ledger because several different payment histories can produce the same balance.

Keep invoice, receipt and fulfilment as separate records

An invoice describes what the customer owes under a pricing policy. A receipt records an accepted payment. Fulfilment records what the business delivered. They answer different questions.

For a direct Solana payment, an invoice should identify cluster, exact asset mint, amount, receiving relationship, correlation reference and expiry policy. A receipt needs a unique transaction or instruction identity, actual received amount and validation evidence.

A fulfilment record links the business action to the invoice. Its uniqueness rule should prevent two workers from delivering the same order twice.

Do not use wallet balance as the invoice table. A balance can change through refunds, internal transfers or several customers paying at once, and it does not identify their intended orders.

Validate candidate receipts before assigning them

A discovery source can report a signature referencing an invoice or receiving account. Fetch and decode the actual transaction under the supported format and program rules.

Require accepted execution and the finality your business policy needs. Check the exact mint, destination relationship, amount and reference. A failed transfer attempt does not become a receipt because its signature appears in history.

Save the relevant evidence and decoder version. If the payment uses a processor, verify event authenticity and the authoritative payment state under that processor's contract.

Keep unsupported or unavailable data in an unresolved queue. Silently interpreting a missing transaction as no payment can leave a customer charged without a matched invoice.

Work a 25-USDC invoice through several receipts

Choose invoice INV-104 for 25 USDC. A first validated receipt R1 contains 20. Under a chosen partial-payment policy, the ledger records 20 received and 5 outstanding.

Receipt R2 contains 5. The validated total reaches 25, so the invoice becomes eligible for fulfilment. A durable unique fulfilment record activates access once.

The discovery worker later sees R2 again during a history overlap. Its unique receipt identity prevents adding another 5. The invoice total remains 25.

A distinct later receipt R3 contains another 25 with the same reference. That is actual additional money, not duplicate delivery of the same event. Record it as an overpayment exception instead of deleting it or fulfilling again.

A duplicate event adds no new money

A duplicate event adds no new money. R1 received: +20 USDC. R2 received: +5 USDC. R2 reported again: +0 USDC. Invoice paid: 25 USDC. Distinct R3 excess: +25 USDC.
Chosen 25-USDC invoice. Deduplicate observations while preserving actual additional transfers.

Model the exceptions as funds requiring a decision

A late receipt can be financially real after the invoice's quote expires. Keep its amount and identity while applying the defined late-payment policy.

A wrong mint, wrong network or unrecognized destination must not satisfy the intended invoice. Recovery depends on the actual service and control of the received asset; do not promise automatic reversal.

An unmatched reference needs investigation. Reusing one public reference for many invoices can make matching ambiguous, even if the token transfer itself is valid.

For refunds, record the approved amount, destination validation, refund transaction and final result. A refund is a new operation with its own possibility of uncertain delivery or duplication.

Reconcile treasury and processor records as another layer

Invoice-level accounting explains customers. Treasury reconciliation explains where the received value went: receiving wallets, internal transfers, processor balances, conversion and bank payout.

Choose a simple teaching processor record: 25 units gross, a disclosed 0.50 service charge and 24.50 net credit. Those are illustrative fees, not a current provider quote. Store gross, charge and net separately.

A bank payout can combine several settlements or occur later. Link its provider ID and bank evidence to the appropriate settlement records. The onchain signature alone does not prove bank receipt.

Investigate differences using exact units and dates. Currency conversion, service deductions and time boundaries should not be hidden inside an unexplained net figure.

Make the ledger survive restarts and parallel workers

Use durable uniqueness for receipt identity and fulfilment operation. Commit the match and queued fulfilment under a transactional design so a crash cannot lose the intended side effect.

External delivery needs its own retry and idempotency contract. A transactional outbox can preserve work for a worker after the database commits. The destination must still support safe repeated delivery or an equivalent acknowledgement design.

Reconcile live events with periodic historical coverage. Advance the cursor only after processing is durable, and expose any source gap which prevents a complete comparison.

Test partial payment, duplicate event, distinct duplicate transfer, late receipt, callback reordering and crash after settlement. The idempotency guide explains the once-only action boundary.

Common questions

Are two reports of one signature two payments?

No. Deduplicate the same receipt identity. A different transaction carrying another transfer is actual additional money to account for.

Should an expired invoice’s receipt be ignored?

No. Record the funds and apply an explicit late-payment or exception policy.

Does paid mean fulfilled?

They are separate states. A valid receipt can exist while delivery is still pending or needs recovery.

Sources and documentation

Found an error or an outdated detail? Send a correction.