Duplicate Customers in QuickBooks Sync: How to Fix

The payout hits the bank at 4,182.63. The four invoices it was meant to cover come to 4,310.00, the processor's report shows 127.37 in fees, and that part is arithmetic anyone can do in their head. The problem sits further up, in a duplicate customer the sync minted three days after cutover. One copy holds eleven years of history and no recent activity. The other holds three weeks of new invoices and nothing behind them, and two of those four belong to it. Undeposited funds, meanwhile, has been climbing since the changeover with nobody able to say what is in it.

No error has been raised anywhere along that chain. The connector's dashboard shows a green tick and a run history with no gaps, and it is telling the truth: every record it was asked to move, it moved.

This is the other half of what breaks after a switch, and it is the opposite shape of the automation layer going quiet. There the failure is absence — the trigger stops firing and no record moves. Here every record moves, on time, and the totals stop agreeing with each other. That is harder to spot and much harder to unwind: by the time the difference is large enough to notice, six weeks of postings are sitting on top of the cause.

One boundary before the mechanics. Everything below is about how the plumbing behaves — which field the connector matches on, which account a payment lands in when nobody names one, what the deposit is made of. Whether a given posting is the right treatment for your books is a question for your accountant, and the answer moves with the entity, the jurisdiction and the chart of accounts. Mechanism here, judgement there.

The error list is already in dependency order

Jobber publishes something most connector vendors leave implicit. Its guidance for resolving QuickBooks Online sync errors says that when errors span different items there may be a cascading effect, and that they should be resolved in this order: clients, products and services, invoices, then payments, refunds and tips as a single step, and payouts last (Jobber Help Center, checked 22 August 2026).

Read that as a diagnostic rather than a to-do list. The payout sits last because a payout is a claim about a set of payments; a payment is a claim about an invoice; an invoice is a claim about a customer. The same page spells out each link. An invoice fails with the message that the client is not in sync. A payment fails with missing invoice in QuickBooks. And the payout error names the invoices whose payments have not been pushed to QuickBooks Online, which is a payout error telling you, in the vendor's own words, that the problem is two levels up.

So the unreconciled payout on your screen is usually a symptom of something that went wrong four steps earlier, generally in the customer list, generally in the first week. Which is why a migration produces this particular failure so reliably. The first week after cutover is exactly when the customer list on the operational side has been newly rebuilt and no longer matches the one the ledger has been accumulating for a decade.

Name is the only key most connectors have

Both major small-business ledgers enforce uniqueness on a display name, and both end up using that name as the matching key when an external system offers nothing better.

Intuit's API reference for the Customer entity states that the DisplayName attribute must be unique across all Customer, Vendor, and Employee objects, and that where DisplayName is not supplied the system generates it by concatenating Title, GivenName, MiddleName, FamilyName and Suffix (Intuit developer docs, checked 22 August 2026). Two things follow. The namespace is shared with suppliers and staff, so a customer who is also a subcontractor collides with himself. And if the connector sends name parts rather than a display name, the ledger assembles the key itself, out of whichever parts the new system happened to populate.

Xero draws the line in a slightly different place. The validation message published in Xero's own OpenAPI specification says the contact name is already assigned to another contact and that the contact name must be unique across all active contacts (XeroAPI/Xero-OpenAPI on GitHub, checked 22 August 2026). Active is doing work in that sentence. Xero contacts carry a ContactStatus of ACTIVE or ARCHIVED, and the rule is written against the active set; the QuickBooks rule as documented carries no equivalent qualifier. If your cleanup plan is to archive the duplicate and re-sync, the two ledgers will not behave the same way, and neither vendor promises the behaviour you are hoping for. Intuit's Customer reference also attaches a consequence to that route: if there is an amount in Customer.Balance when the object is set to inactive through the QuickBooks UI, a CreditMemo balancing transaction is created for the amount. Test it on one record before you plan around it.

The same Xero specification describes a field built for precisely this problem and almost never filled in. ContactNumber can be updated only through the API, is read-only on the Xero contact screen, and is documented as being used to identify contacts in external systems. A stable external key, sitting there unused, while the connector matches on a string somebody typed by hand.

Now add what happens to that string in transit. Jobber's error documentation lists a warning for character limit exceeded, explaining that the field exceeds QuickBooks Online's character limit and was truncated, and another for invalid character, where the offending character is replaced in QuickBooks Online. Both are warnings. The record syncs. And the name held by the ledger is no longer byte-for-byte the name held by the operational system, so the next match attempt misses and creates a second record.

Which brings me to the setup line that reads like a tip and is really a specification. Jobber's setup guide asks whether you have clients in both your Jobber and your QuickBooks Online account, and answers that if you do, syncing can cause duplicate client profiles in both systems — so they suggest either the QuickBooks account or the Jobber account does not have clients in it before syncing (Jobber Help Center, checked 22 August 2026). A migration guarantees the condition they are warning about. Both sides are populated, by definition, because you have a ledger with history and a new operational tool you have just imported everything into.

Note what none of these pages offers: a second key. Neither ledger's documentation promises a fallback to the email address when the name misses, and the connector's own answer to the duplicate question is to keep clients off one of the two sides rather than to reconcile them. Until a vendor page says otherwise, assume the name is the whole of the match.

Merging is the cleanup both ledgers provide, and it is an operation to test on a single pair before running it across a list — treat it as irreversible until you have proved otherwise in your own file, because undoing it means re-creating a record that no longer has its transactions attached.

The cheap version of all this is a name reconciliation done before the first sync. Export the contact list from the ledger and the customer list from the new tool, match on nothing but the exact string, and look at the rows that do not pair. Trailing spaces. Ltd against Ltd.. An ampersand where the other side spelled the word out. A trading name against a legal name. That list is the count of duplicates you are about to create, and it is far quicker to fix in a spreadsheet than in a ledger.

Undeposited funds is a default, not a decision

The account fills up for a reason that is written down in one sentence. Intuit's API reference for the Payment entity says of DepositToAccountRef that if you do not specify this account, payment is applied to the Undeposited Funds account (Intuit developer docs, checked 22 August 2026). No account named, no error raised, funds parked. Newer QuickBooks Online files show the same account labelled payments to deposit, and connector documentation tends to name both spellings when telling you where to point things.

Good connectors use it deliberately, as the first half of a two-stage posting. Jobber's payouts documentation describes the second half: payments appear in undeposited funds until the payout that includes the payment is initiated and synced, at which point they are transferred to your checking account (Jobber Help Center, checked 22 August 2026). The same page lists the accounts the sync creates as needed, and the list is longer than most people expect: a payments fees account, undistributed tips, instant payout clearing, refunds clearing, an allowance for disputed payments, and loan accounts where a processor advance is involved.

So a rising undeposited funds balance after a switch is nearly always one of three states, and they are easy to tell apart:

  • Payout syncing was never enabled. The payment half posts, the deposit half does not exist. The balance grows by roughly your gross takings and never falls.
  • Payout syncing is enabled and erroring. The balance grows in steps, and the connector's error list has entries under payouts that point at invoices or payments further up the chain.
  • Somebody cleared it by hand. The balance looks healthy and the next payout fails.

That third state deserves the warning, because it is the natural instinct and the expensive one. Jobber documents the failure plainly: where you manually adjusted the deposit-to account on payments belonging to a payout, the instruction is to revert it to undeposited funds or payments to deposit and retry, and where you built the bank deposit yourself, the instruction is to delete the entire bank deposit from QuickBooks and retry. The connector was going to assemble that deposit. It cannot, because your entry already occupies the position, so it errors — and the error surfaces days later, attached to a payout rather than to the thing you did.

There is also a version of this that is purely a naming problem. One of the documented errors reads that an "Undeposited Funds" account was not found in QuickBooks Online. If the chart of accounts was rebuilt or tidied during the move — which happens more often than people admit, because a fresh file feels like a fresh start — the connector is hunting for a string that no longer exists in your ledger.

The deposit is net, the invoices are gross, and the dates are offset

Even with a clean customer list and payout syncing running, the number that lands in the bank will not equal any set of invoice totals. Three mechanisms, all structural.

Fees come out per transaction, not per payout. Stripe's balance transaction object describes net as the net impact to a Stripe balance, and says you can calculate it as amount minus fee (Stripe API reference, checked 22 August 2026). The customer paid the gross. The balance received the net. Nothing in between appears on the bank statement.

A payout is a batch of mixed things. Stripe's payout reconciliation guide says automatic payouts occur routinely according to your payout schedule and can include funds from multiple transactions, and that the balance transactions making up a payout carry types including charge, refund, stripe_fee and payout itself (Stripe docs, checked 22 August 2026). A refund issued on Tuesday reduces Thursday's deposit. So does a dispute, and so does the repayment of a processor advance where one exists.

The window is shifted, not aligned. Stripe's payouts page gives the example outright: an account set to daily payouts with a 3-business-day settlement timing has Stripe paying out funds daily from transactions that were captured three business days earlier (Stripe docs, checked 22 August 2026). The deposit dated the fourteenth is the eleventh's takings, less the eleventh's fees, less anything refunded since. Weekends make the offset uneven, which is why the mismatch resists being explained by a single percentage.

Two special cases will otherwise eat an afternoon. Stripe states that because you control the timing and amount of manual payouts it cannot identify which transactions are included, leaving that reconciliation to you. And Jobber notes that instant payouts cannot be reconciled until the next standard payout is created, at which point the instant amount is deducted from both the standard payout and the clearing account. If somebody pressed the instant payout button during changeover week — and somebody usually does, because cash feels tight during a changeover — that is where the unexplainable line came from.

Xero files get one extra artefact from the same cause. Xero's Payment schema documents Amount as the amount of the payment, which must be less than or equal to the outstanding amount owing on the invoice. Post the net figure against a gross invoice and the invoice is not paid; it is short by the fee. An invoice for 480.00 settled with a payment of 465.78 leaves 14.22 outstanding, indefinitely, against a customer who has paid you in full. Multiply that by a few hundred invoices and the receivables ageing report becomes fiction.

Settlement-first posting is the shape that reconciles

There is another way to post all this, and once you have seen it the fee-sized residue stops looking like something to chase invoice by invoice. A2X, which sends marketplace and processor settlements into both ledgers, describes the mechanism in its QuickBooks documentation: the settlement goes over as a journal, and QuickBooks Online auto-matches it because the amount of the journal matches the amount of the settlement deposit. Where a settlement period straddles a month end it is split into two journals dated accordingly, and you still reconcile to one bank entry (A2X Support Center, checked 22 August 2026).

The shape is the point, not the vendor. One entry per deposit, whose total equals the bank line by construction, with sales, fees, refunds and taxes broken out inside it. The other shape has to assemble a set of customer payments into one deposit and find the fees somewhere, so it reconciles only when every upstream record is correct — which is the condition a migration has just removed. If your connector works that way, that is why it is fragile in week one.

Four numbers, taken before you change anything

Diagnosis first, from four independent places, for a single window. One week is enough. Pick a week that falls entirely after cutover.

Number Where it comes from What a gap tells you
Gross invoiced in the window The operational tool's own sales report Compare against the ledger's income for the same dates — a gap here is invoices that never synced
Gross, fees and net per payout ID The processor's payout or settlement report The only place all three appear together; this is your control total
Deposits actually received The bank statement, not the bank feed A feed can be missing days without announcing it
Undeposited funds closing balance The ledger's account register If it is not roughly one payout cycle of takings, the two halves of the sync are out of step

Then one figure that is not a currency amount: the customer count on each side, from the same two exports as the name reconciliation above. The duplicate problem appears here as a number days before it appears as a reconciliation difference.

Write those five figures down with the date and the URL of each report. A bookkeeper brought in later asks for exactly this, and capturing it now is far cheaper than reconstructing it from a system you have since disconnected. The 30-day switch runbook puts this step inside the parallel-running window, which is where it belongs — while both systems are open and both still answer.

Record the mapping before you disconnect the old connector

One window closes for good the day you disconnect, and hardly anybody photographs it first.

A connector's settings screen is the only written record of decisions made months ago: which ledger account each transaction type maps to, which bank account payouts post into, which tax rates correspond to which, when the sync was switched on, and whether history was backdated. Revoke the integration and that table goes with it, along with the error list — the unresolved entries in which are the index of everything that never made it across.

So screenshot every page of the sync settings first, export the full error and warning list, and note the ID and date of the last payout that synced successfully. That last one is the boundary between the period the connector handled and the period a human has to, and its location is the first question at year end. The rest of what to take off the old side is in the pre-cancel checklist; these three are the accounting-specific additions to it.


Verified against Intuit, Xero, Stripe, Jobber and A2X documentation on 22 August 2026, at the pages linked above, and two of them repay opening yourself. The Intuit and Xero references are field-by-field schemas, so each sentence quoted here sits beside qualifiers that may apply to your setup and not to the next reader's. Jobber's error catalogue describes one connector — cited this heavily only because it is the vendor that publishes its failure modes in public, which is a point in its favour rather than a verdict against it. Nothing above ranks a product or settles an accounting question. Vendor pages also get rewritten without a changelog, so the date is the edge of what this page knows: a claim that no longer matches its source can go to the contact form, and the about page sets out why every page carries one.

Frequently asked questions

Why did the sync create a second customer that already existed?

Because the connector matched on the name, and the name changed on the way in. QuickBooks Online's API reference for the Customer entity says the DisplayName attribute must be unique across all Customer, Vendor, and Employee objects, and that if you do not supply one, the system generates it by concatenating Title, GivenName, MiddleName, FamilyName and Suffix. Xero's position is similar but not identical: the validation message published in Xero's own OpenAPI specification reads that the contact name is already assigned to another contact and must be unique across all active contacts. So the ledger has a single text field acting as a primary key, and anything that rewrites that text breaks the match. Jobber's QuickBooks error list documents two rewrites that happen inside the sync itself: a field that exceeds QuickBooks Online's character limit is truncated, and a name containing an invalid character has that character replaced. Both are logged as warnings rather than errors, so the record syncs and the name in the ledger quietly stops being the name in the source. All three pages checked 22 August 2026.

Why is the undeposited funds balance growing after the migration?

Usually because only half of the sync is running. Undeposited funds is a default rather than a choice: Intuit's API reference for the Payment entity states that if you do not specify a DepositToAccountRef, the payment is applied to the Undeposited Funds account. Connectors post customer payments there deliberately and then clear them when the corresponding payout syncs. Jobber's documentation describes exactly that sequence: payments appear in Undeposited Funds until the payout that includes the payment is initiated and synced to QuickBooks, at which point they are transferred to your Checking account. If payout syncing was never switched on, or the payouts are erroring, the first half keeps posting and the second half never arrives. The balance is the count of payments waiting for a deposit that is not coming. Both pages checked 22 August 2026.

Why doesn't the payout in my bank match the invoices it paid?

Three separate reasons, and they stack. Fees: Stripe's balance transaction object defines net as amount minus fee, so what leaves the processor is smaller than what the customer was billed. Batching: Stripe's payout reconciliation guide says an automatic payout can include funds from multiple transactions, and the balance transactions inside it carry types such as charge, refund, stripefee and payout, so refunds and fee lines are mixed in with the sales. Timing: Stripe's payouts documentation gives the example of an account set to daily payouts with a 3-business-day settlement timing, where Stripe pays out funds daily from transactions captured three business days earlier, so the deposit dated the fourteenth is not the fourteenth's invoices. Manual payouts are harder still: Stripe states that because you control their timing and amount, it cannot identify which transactions are included in each payout. Pages checked 22 August 2026.

Can I just fix it by hand in the accounting software?

You can, and on a live connector it tends to make the next sync fail instead. Jobber's payout error documentation is unusually direct about this. If you manually adjusted the deposit-to account on payments belonging to a payout, the fix is to revert it to undeposited funds or payments to deposit and retry. If you recorded the bank deposit yourself, the instruction is to delete the entire bank deposit from QuickBooks and retry. The connector is trying to assemble that deposit and cannot, because something is already sitting where it intended to write. Manual entries belong to periods that are closed, or to the time after the connector is disconnected for good. Page checked 22 August 2026. Whether any of these postings is the right treatment for your books is a question for your accountant, not for this page.