Payment reconciliation across many PSPs: a practical model
Reconciling across several PSPs means matching three records: your orders, each provider's transactions, and the settlement credits that reach your bank. Carry one merchant reference on every request, load each provider's settlement report into one common format, match transactions by reference and amount, then match each settlement batch, net of fees, refunds and chargebacks, to a bank credit. Unmatched items are usually timing, fees or FX, and need an owner.
In 30 seconds
- Reconcile in three layers: your orders against provider transactions, then provider settlement batches against bank credits.
- Carry one merchant reference on every payment, refund and payout, so every provider report can be joined to your ledger.
- Most breaks are timing, fees netted from settlement, FX and refunds or chargebacks landing in a later batch, not lost money.
- 4 sources cited
On this page9 sections
With one payment provider, reconciliation is a monthly chore: download the provider’s report, tick it against the bank statement, explain the difference. With four providers across six currencies, and local methods that settle on different calendars, it becomes a daily operation, and the gaps in it are where money quietly goes missing.
This article sets out a practical model for reconciling payments across several providers: the three layers to match, the identifiers to carry, a common data model, the rules that do the matching, and the breaks that cause most of the work. It is written for finance and payment teams at merchants that already route payments to more than one PSP.
What does payment reconciliation actually match?
Three records, in two steps.
- Orders against provider transactions. Every order your system marked paid should have a successful transaction at a provider, for the same amount and currency, and every successful transaction should belong to an order. This catches orders shipped without payment and payments taken without an order.
- Provider settlements against bank credits. Every settlement batch a provider says it paid should arrive in your bank account for the net amount, and every credit in the bank should belong to a batch. This catches missing payouts, unexpected deductions and fees you did not agree to.
Between the two steps sits the settlement report: the provider’s list of what went into each batch. Stripe’s payout reconciliation report, for example, matches each automatic payout to the payments, refunds, disputes and fees it settles. Adyen’s settlement details report does the same per merchant account and per batch, with entry types such as Settled, Refunded, Chargeback, Fee and MerchantPayout.
Why is it harder with several PSPs?
Each provider describes the same events differently. The differences that matter:
| Difference | Example | What it breaks |
|---|---|---|
| Report format | Column names, sign conventions, file per batch or per day | Any rule written for one provider |
| Fee presentation | Fees netted per line, per batch, or invoiced monthly; Adyen splits interchange, scheme fees and markup only when the acquirer provides the data | Gross to net checks |
| Timing | Stripe pays 2 business days after a card payment in the US and Australia; ACH Debit takes 4 business days | Daily matching windows |
| Batch dating | Stripe groups payouts by estimated arrival date, not the date the bank posts them | Bank statement matching on date |
| Currency | Settlement in local currency, USD or EUR, with FX at the provider | Amount matching |
| Identifiers | Each provider has its own transaction ID | Joining to your orders |
Local methods add their own calendars. A voucher paid in a store in Mexico or a bank transfer in Colombia confirms later than a card, and may settle on a different cycle from the same provider’s cards.
Which identifiers should every transaction carry?
The single most useful decision is to send your own merchant reference with every request: payment, refund, payout, and any retry or cascade attempt. Adyen’s report, for instance, lets you match entries on both the provider’s reference and the merchant reference. If every provider returns your reference, joining their reports to your ledger becomes a lookup, not a puzzle.
Keep, for every transaction:
- Your order or merchant reference, identical across all attempts at all providers.
- The provider’s transaction ID for the attempt that succeeded.
- The provider and merchant account that processed it, since one provider can hold several accounts.
- The settlement batch or payout ID, once the provider reports it.
- The bank reference of the credit that paid the batch out.
With cascading, one order may have a failed attempt at one provider and a success at another. Only the success should appear in settlement; a failed attempt that shows up there is a break to investigate.
What does a common data model look like?
Load each provider’s report into one normalised table. A workable shape:
| Field | Meaning |
|---|---|
| merchant_reference | Your order or operation ID |
| provider, provider_account | Who processed it and under which account |
| provider_txn_id | The provider’s ID for this entry |
| entry_type | payment, refund, chargeback, chargeback_reversal, fee, reserve, payout |
| gross, fee, net, currency | Amounts as reported, signs normalised |
| settlement_currency, fx_rate | When settlement differs from the payment currency |
| batch_id, expected_payout_date | From the settlement report |
| bank_reference, bank_date | Filled when the bank credit is matched |
| match_status, break_reason | matched, pending, break, and why |
Normalising signs and entry types is most of the work. After that, the same match rules run for every provider.
How do the match rules work?
Run them in order, from the strictest to the loosest:
- Exact match on merchant reference, amount and currency.
- Match on provider transaction ID where the reference is missing, for example on chargebacks initiated by the issuer.
- Link child entries (refunds, chargebacks, reversals) to the original payment by its reference, whatever batch they arrive in.
- Check each line’s arithmetic: gross minus fee equals net. Adyen’s documentation describes commission as gross minus net, and notes negative commission values can appear on some refunds, so allow for them.
- Sum each batch and match its net total to one bank credit by amount, currency and a date window.
- Everything else goes to a break queue with a reason.
Example figures, for illustration only. A merchant processes 60,000 payments a month across three providers. After exact matching, 58,900 are matched. Rules 2 and 3 clear another 900 refunds and chargebacks. The remaining 200 are timing differences that clear in the next batch, plus 6 real breaks: two duplicate captures, three fees above the contract rate and one payout that never arrived. Those 6 items are what the reconciliation is for.
What causes most reconciliation breaks?
- Timing. The batch has been reported but the bank credit has not arrived, or the other way round. Stripe notes that a payout can arrive before its reconciliation data is ready.
- Fees. Deductions that differ from the contract, or monthly invoices that the batch does not show.
- FX. Settlement in a different currency from the payment, at a rate you cannot see per transaction.
- Refunds and chargebacks deducted in later batches than the original payment.
- Reserves. Amounts held back under a rolling reserve and released months later.
- Instant or manual payouts. Stripe says it cannot identify which transactions are included in instant payouts, because the merchant controls their timing and amount.
- Status mismatches. An order marked failed whose payment succeeded later. This is why the order status should follow the webhook, not the browser redirect; our guide to webhooks and idempotency covers the handler side.
Who should own each kind of break?
A break queue without owners grows until month end. Assign each reason code to a team when you design the rules, not when the queue is full:
| Break | Owner | First action |
|---|---|---|
| Paid order with no successful transaction | Payments operations | Look up the status at the provider; hold the order if unpaid |
| Successful transaction with no order | Engineering | Check webhook delivery and the order service logs; refund if no order can be created |
| Fee above contract rate | Finance | Raise with the provider’s account manager with the batch and line references |
| Batch reported, no bank credit | Treasury | Ask the provider for the payout trace or bank reference |
| Chargeback with no original payment found | Risk | Match by provider ID and card details; check for a payment taken through another account |
Review the queue’s age every week. Items that keep reappearing with the same reason usually point to a rule that needs changing, not to a provider error.
How often should you reconcile?
Daily for transactions, and per batch for settlements. Daily matching finds an order shipped without a successful payment while the customer can still be contacted, and finds a provider outage that left payments in limbo. Batch matching finds missing payouts and unexpected deductions before the month-end close, when they are still easy to raise with the provider.
How does Omno help with reconciliation?
Omno puts one transaction record and one set of statuses in front of every connected provider, with webhooks as the source of truth and a merchant reference on each request linking Omno’s transaction ID to your ledger. The routing-decision log shows which provider processed each payment and every cascade attempt, and reporting and data export provide transactions and summaries for reconciliation and finance tools. The reporting and analytics page covers the dashboard and exports; settlement files still come from each provider, so the bank-side match stays with your finance team.
Key facts
- Stripe's payout reconciliation report matches each automatic payout to the batch of payments, refunds, disputes and fees it settles, but cannot do so for instant payouts, which the merchant times itself (Stripe docs, 2026).
- Stripe groups a payout by its estimated arrival date, not the date the bank posts it, and report data can be ready after the payout arrives (Stripe docs, 2026).
- Adyen's settlement details report is generated per merchant account and per batch, with entry types such as Settled, Refunded, Chargeback, Fee and MerchantPayout (Adyen docs, 2026).
- Adyen reports interchange, scheme fees and markup in separate columns only when the acquirer provides interchange-level data; otherwise the total sits in one commission column (Adyen docs, 2026).
- Stripe's settlement timing varies by country, for example 2 business days in the United States and Australia, while ACH Debit takes 4 business days (Stripe docs, 2026).
Changelog
- First published.
Sources
4 references
- Payout reconciliation report, Stripe
- Payouts, Stripe
- Settlement details report, Adyen
- Handle webhook events, Adyen