Skip to Content

How We Automated Payment Reconciliation for 4 PSPs in Odoo 18

A case study in automating Stripe, PayPal, Klarna, and Revolut reconciliation — with real production numbers

Stripe deposits €11,820 — but inside there are 47 charges, 3 refunds, and €340 in fees. PayPal sends €4,200 with no breakdown. Klarna settles in SEK. If you use Odoo with multiple PSPs — you know this pain. Here's how we went from 6 hours of manual reconciliation per month to zero.

Why reconciliation in Odoo is painful

Odoo 18 has solid bank reconciliation for simple cases. One customer payment comes in, it matches one invoice, you click validate. Done.

But PSP payouts don't work that way. When Stripe sends money to your bank, it doesn't send one payment per order. It bundles days of charges into a single deposit, subtracts refunds and processing fees, and sends one lump sum. Your bank sees one line: "STRIPE PAYOUT €11,820." Odoo has no idea what's inside that number.

Stripe does have a native payment module in Odoo 18. But here's the catch — it only works if Stripe is connected directly to your Odoo website. If your customers pay through an external e-commerce platform that routes payments through Stripe — that module is useless.

PayPal? No native payout reconciliation. Klarna? Not even a native payment module. Revolut? Same story. The community has been asking for years. Forum threads with thousands of views describe the same pain: manual CSV exports, Excel reformatting, hours of clicking through the reconciliation widget.

PSP Native External Payout Recon Ours
Stripe
direct
PayPal
basic
Klarna
Revolut

Stripe's native module works only when connected directly to your Odoo website.

Our setup: two businesses, one Odoo

We manage two e-commerce companies from a single Odoo 18 instance on Odoo.sh.

Company A is a local retail operation running on an Odoo-powered website. Payments go through Stripe and PayPal, settling into a EUR bank account.

Company B handles international sales across multiple European markets through an external e-commerce platform — completely separate from Odoo. Payments come through Stripe (not connected to Odoo), Klarna (for Scandinavian customers paying in SEK, DKK, NOK), and Revolut.

Both companies' bank accounts are connected to Odoo via Saltedge. Bank statements arrive automatically. But matching those bank lines to actual customer orders? That was entirely manual.

Company A Local retail • Odoo site Company B International • External Stripe PayPal Stripe Klarna Revolut Bank Account A EUR Bank Account B EUR • SEK • DKK • NOK Bank Account C GBP • CHF Odoo 18 Saltedge

Four PSPs, multiple currencies, three bank accounts, two companies — all converging into one Odoo 18 instance.

So what happens when Stripe sends a payout?

Most Odoo users don't fully understand how PSP payouts work. Here's the reality.

A customer places an order for €899. Stripe creates a charge. Over the next few days, more customers buy things. Stripe collects all these charges. On payout day, Stripe calculates: all charges minus refunds minus its processing fees. Then it sends one transfer to your bank.

Your bank shows one deposit. Odoo imports it as one bank statement line sitting in a suspense account, waiting for someone to figure out what it means.

Anatomy of a Stripe Payout

47 charges +€12,340
3 refunds −€180
Stripe fees (2.7%) −€340
Bank deposit =€11,820
  Odoo sees: 1 bank line for €11,820
Odoo doesn't know: what's inside

Building the solution, one PSP at a time

We didn't set out to build a universal reconciliation engine. We started with one problem and kept going.

Month 1 — Stripe first. The plan was simple: connect to the Stripe API, fetch all charges, match each one to a sale order by reference, auto-reconcile. It worked for about 80% of transactions on day one.

Month 2 — PayPal joins. PayPal was a different beast. Unlike Stripe, PayPal has no settlement API. We had to invent "synthetic payouts" — find bank lines containing "PAYPAL" and figure out which transactions fit each deposit by date range and amount.

Month 2.5 — Klarna enters. Klarna brought the multi-currency surprise. Customers in Scandinavia pay in SEK, but Klarna settles in EUR. Our coverage check was comparing amounts in different currencies. It took two days to trace this bug.

Month 3 — Revolut completes the set. The simplest integration: one charge, one payout. But even this had a quirk — Friday orders settle on Monday, so the matching window needed to accommodate weekends.

Month 1

Stripe integration

Month 2

+PayPal, synthetic payouts

Month 2.5

+Klarna, multi-currency

Month 3

+Revolut, 1:1 matching

Now

Auto-undo, backfill, fee fix

The problems we didn't expect

The initial integrations were the easy part. The real work was handling edge cases that only show up in production.

Orphaned charges

Stripe had charges that didn't match any order in Odoo. Test transactions, manual charges, charges from a website we didn't know was on the same Stripe account. The first version crashed on these. Now it flags them as exceptions and moves on.

Odoo "helping" too much

Odoo's built-in reconciliation model is eager — it grabs bank lines and partially reconciles them before our module runs. Wrong matches, half-done journal entries. We had to build auto-undo logic: detect, reverse, redo properly.

PayPal's missing settlement API

Stripe and Klarna have settlement endpoints. PayPal doesn't. We reverse-engineer payouts from bank lines by date gaps and amounts. Edge cases include PayPal holding funds for security — potential refund reserves can delay settlements from 7 to 49+ days.

Fees & multi-currency

Each PSP deducts fees differently — per-transaction, per-payout, or silently from the settlement. Add multi-currency on top (Klarna charges in SEK, settles in EUR) and the numbers never match on the first try. There are a lot of tricky situations with fee handling that only surface in production.

How it works now

One Odoo module. Five daily cron jobs. Zero manual intervention.

TimeWhat happens
05:30Sync order references from external platforms
06:00Fetch transactions from all four PSP APIs
06:30Match transactions to orders, payouts to bank lines
07:00Reconcile — rewrite journal entries, book fees
09:15Telegram morning report

If something goes wrong — a missing order reference, an invoice not yet created — the transaction is flagged as an exception with a clear reason. An accountant can resolve it through a wizard showing suggested matches.

If Odoo's built-in reconciliation interferes, the auto-undo kicks in, reverses the damage, and retries.

The results: real numbers from production

These numbers come from our production Odoo instance, covering roughly 2.5 months of operation.

231
transactions
€243K
reconciled
74
payouts processed
4
PSPs integrated
99.6%
success rate
€3.5K
fees tracked
~6h
saved monthly
2
companies

One exception out of 231 transactions — a PayPal charge with no extractable order reference. In our latest month: 31 payouts totaling €99,674 across all four PSPs.

PSPTXPayoutsAvg TX
Stripe163334.5
PayPal47212.0
Klarna1091.1
Revolut11111.0

Before and after

Before

47 transactions to match by hand
× 4 minutes each
= 3+ hours of manual work
Rounding errors, suspense entries
End-of-month stress

After

1 automated daily cron
0 manual intervention
0 suspense
Telegram report at 9 AM
Coffee time

If this sounds familiar

If you're running an e-commerce business on Odoo with multiple payment providers and your accountant is spending hours matching bank statements to orders — we've been exactly where you are.

Our module runs daily, handles four PSPs, two companies, and multiple currencies. We built it for our own businesses and we can adapt it for your business too.

Want to talk about your setup?

We're happy to walk through how automated PSP reconciliation could work for your Odoo instance.

Get in touch →
How to Schedule Out-of-Hours Auto Replies in Odoo with Auto Reply Schedule