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.
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
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.
| Time | What happens |
|---|---|
| 05:30 | Sync order references from external platforms |
| 06:00 | Fetch transactions from all four PSP APIs |
| 06:30 | Match transactions to orders, payouts to bank lines |
| 07:00 | Reconcile — rewrite journal entries, book fees |
| 09:15 | Telegram 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.
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.
| PSP | TX | Payouts | Avg TX |
|---|---|---|---|
| Stripe | 163 | 33 | 4.5 |
| PayPal | 47 | 21 | 2.0 |
| Klarna | 10 | 9 | 1.1 |
| Revolut | 11 | 11 | 1.0 |
Before and after
Before
After
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 →