Skip to content

QuickBooks Two-Way Sync: Odoo QuickBooks Online Connector with a Conflict Queue and Proof the Two Ledgers Agree

Two-way QuickBooks Online sync that stops and asks when the two sides disagree.

What it does

QuickBooks Two-Way Sync moves twenty QuickBooks Online objects between Odoo and QuickBooks, and you switch each direction on per object. If someone edits the same record on both sides, the sync stops. It lays the two versions out field by field and waits for you to choose. It is built for a business that keeps its books in QuickBooks and runs its operations in Odoo.

The problem it solves

One-way sync is easy. Two-way sync is where the books start to drift. Someone in Odoo edits the address on an invoice. At the same time, someone in QuickBooks changes the amount on that invoice. Most connectors settle it by writing the version they happened to read second, and nobody notices until month-end refuses to tie. Then there are writes that cannot be made correctly: a tax nobody has mapped, an item QuickBooks will not accept, a payment the platform has already locked. A connector that guesses at those puts a wrong number into somebody's filing.

Platform
Odoo
Category
Connectors
Works with
Odoo 18 · Odoo 19
Technical name
qbo_sync
Status
Published on the Odoo App Store
On the store
Odoo 19 Odoo 18
Pricing
Paid

What comes in the module

  1. 01

    A conflict, field by field

    The record goes to a Conflicts queue. Both versions are flattened to the same field paths and compared row by row, as deep as Line[0].SalesItemLineDetail.UnitPrice. You pick keep Odoo, keep QuickBooks or ignore, and picking keep QuickBooks reads the record again, live, before anything is applied. Each successful write saves the QuickBooks SyncToken, the QuickBooks timestamp and the Odoo write date, so when your own change comes back through the feed it is spotted and dropped.

  2. 02

    Proof that the two ledgers agree

    It reads QuickBooks' own reports and sets the two receivable balances next to each other, then lists the documents behind any gap with a button on the same screen that sends the missing ones. Beside it sit eleven numbers, the first of which is how stale the change feed is, because a connector that has stopped talking looks exactly like one with nothing to do.

How it plays out day to day

  1. The same invoice changed in Odoo and in QuickBooks

    Someone edited the address in Odoo. Someone else changed the amount on that invoice in QuickBooks minutes earlier, and neither knows about the other.

    Nothing is written. The invoice goes to the Conflicts queue, where both versions sit on the same field paths, as deep as Line[0].SalesItemLineDetail.UnitPrice. Someone then picks keep Odoo, keep QuickBooks or ignore.

    Behaviour of the shipped code.

    A conflict, field by field

  2. An invoice line carries a tax with no QuickBooks code

    The line has an Odoo tax nobody has mapped to a QuickBooks tax code. Guessing a rate would put a wrong number in a filing.

    The job stops in a Blocked state and prints the instruction itself, naming the Odoo tax and telling you to map it to a QuickBooks tax code. Nothing is skipped and nothing is approximated.

    Behaviour of the shipped code.

    A conflict, field by field

  3. Both receivable balances read the same and still disagree

    The Odoo receivable and the QuickBooks receivable come out level, which is usually taken as agreement and signed off.

    The reconciliation screen lists the documents behind the gap. Two invoices that never arrived and one document that exists only in QuickBooks show up as named rows, so they cannot cancel each other out inside a total. A button sends the missing ones.

    Behaviour of the shipped code.

    Proof that the two ledgers agree

What it won't do

QuickBooks Desktop is a different product
It has a different API too. This connector works with QuickBooks Online only.
No payroll
The Accounting API has no payroll entity. Intuit suggests posting third-party payroll as journal entries, and journal entries do sync.
No bank feeds
The API has no entity for them. Downloaded transactions and the for-review queue stay inside the QuickBooks interface.
No VAT or GST return filing
The API has no filing endpoint. Intuit's engineers have confirmed that the Australian BAS report is not available through it either.
No combo or bundle products
QuickBooks has no single item an invoice line could point at, so put the components on the invoice. If a bundle reaches the export, it blocks and gives the reason. It does not send one component and leave out the rest.

Common questions

Can I install this on Odoo Online?
No. Odoo Online cannot install modules that contain Python, so this runs on Odoo.sh or a self-hosted instance. Check the versions listed above for the series and edition it is verified against.
Does this work with QuickBooks Desktop?
No. QuickBooks Desktop is a different product with a different API, and none of this reaches it. The connector is QuickBooks Online only. If your books are on Desktop, nothing here will help until they move.
Will it sync my payroll or my bank feeds?
No. The API offers neither one to sync. It has no payroll entity, so Intuit's advice is to post third-party payroll as journal entries, and this connector does move those. Bank feeds have no entity either. Downloaded transactions and the for-review queue stay in QuickBooks.
What happens if I restore a production database onto staging?
The connection will not run. It records which database it was authorized from, so a restored copy on staging stops before it can push test invoices into your live QuickBooks company. The same check catches a connection whose QuickBooks company was swapped underneath it.

Have something to build?

Tell us the problem. We'll come back with a plan, a price, and who would build it.

  • Free scoping call
  • Reply within 1 business day
  • No lock-in