← All posts
Workflow · May 31 2026 · 10 min read

Customer part numbers to QuickBooks SKUs: the mapping problem

An electrical distributor stocks a 100A circuit breaker as BRK-100A-2P. One of their best customers, a mid-sized HVAC contractor, has been ordering it for eight years under the part number SQUARE-D-QO2100. The customer's PO never says BRK-100A-2P. The QuickBooks Online item catalog only knows BRK-100A-2P. This single mismatch is responsible for more failed PO automations than any other cause.

Why QuickBooks Online doesn't help

QuickBooks Online has a Name field, a SKU field, and a Description field on every Item. It does not have a customer-cross-reference field. There's no aliases[], no customer_pns[], no link table you can populate.

The workarounds people try, and why none of them scale:

What actually works: a separate cross-reference layer

The fix is a cross-reference table that sits outside QuickBooks. It maps (customer_id, customer_pn) → qb_sku. Three columns. Append-only. Backed by your accounting team's domain knowledge, populated incrementally.

Example rows:

CustomerCustomer PNQB SKU
HVAC Plus IncSQUARE-D-QO2100BRK-100A-2P
HVAC Plus IncSQ-D-QO250BRK-50A-2P
Brightline MechanicalCB-100-DPBRK-100A-2P
Brightline MechanicalBRK-100ABRK-100A-2P
Sierra IndustrialQO2100-SQDBRK-100A-2P

Same QB SKU on three different rows, three different customer PNs. The table doesn't care; that's the whole point.

The parser reads a PO line, sees the customer PN, looks up the buyer in the table, and resolves to the QB SKU. If the customer is new or the PN is new, the line falls through to fuzzy description matching and gets flagged for human review. Whoever reviews the line confirms the match — and that confirmation writes a new row to the cross-reference table. Next time the same customer sends the same PN, it parses cleanly without anyone touching it.

The auto-learning loop

The cross-reference table grows on its own as long as the workflow has a review step. The mechanic is straightforward:

  1. PO comes in with a customer PN the matcher can't resolve.
  2. Matcher falls through to description-fuzzy and returns the top 3 candidates.
  3. Draft gets built with the candidate and a needs_review: cross_reference_unknown flag.
  4. Reviewer opens the draft, confirms (or corrects) the candidate, clicks submit.
  5. The confirmation writes a new row: (this_customer, this_pn, the_confirmed_sku).
  6. Next PO from the same customer with the same PN: zero friction, no flag.

Over 4-6 weeks of normal volume, the table fills out for your active customers. We've measured this on real customer data: in the first 30 days a typical distributor's review rate drops 40-60%, and at week 8 it's stable in the 8-15% range. The 15% that stays is mostly new customers or genuinely new SKUs.

Partial-SKU matching for the messy cases

Not every mismatch is a customer-specific alias. Some are typos, some are dropped prefixes, some are the customer cutting your SKU short. SideQuest v0.15.8 ships a partial-SKU matcher for these.

The rule: if a customer PN starts with or ends with a substring that matches one of your SKUs (4 chars or longer), and the description still rhymes with the catalog item, propose the match with a confidence penalty. Examples from real POs:

Customer PN on POQB SKUMatch type
BR-ELB-050-NPT-XLBR-ELB-050-NPTcustomer added a suffix
BR-ELBBR-ELB-050-NPTcustomer dropped detail
050-NPTBR-ELB-050-NPTcustomer dropped prefix
BRELB050BR-ELB-050-NPTcustomer dropped dashes

Each one of these resolves to the correct SKU but with the line still flagged for review. The point isn't to auto-submit. It's to surface the candidate so the reviewer confirms in one click instead of opening a search.

Pack-size inference

A common shape: customer PO says "1 case of valves," QuickBooks SKU is per-each. SideQuest detects this. The packaging UoM extractor recognizes case, box, pack, dozen, pallet, bundle, roll, pair, set, kit, sleeve, drum, bucket, skid, spool, tube, plus the aliases customers actually type (cs, bx, pk, dz, plt, etc.).

When the customer's UoM doesn't match the catalog UoM, the matcher surfaces a suggestion: "Customer ordered 1 case; your catalog has this as each. Pack size on this item — 25 per case. Want me to multiply qty by 25?" The reviewer confirms. Next time the same customer orders the same SKU in cases, the qty conversion runs automatically and the line clears.

Why the table belongs outside QBO

People ask: why not put the cross-reference in QuickBooks Online via the Description field or a custom field? Three reasons.

First, QBO's data model isn't built for this. Description is a free-text field used by half the team for human-readable notes; cramming structured data in there breaks both uses. Custom fields are limited to three per company. Neither scales beyond a handful of customers.

Second, the table needs to be queryable in two directions: from a PO line, look up the SKU; from a SKU, list every customer alias. QBO doesn't index custom fields for the second direction.

Third, you don't want to mutate the QBO catalog every time a new customer alias appears. The catalog is sacred — it's what your AR team sees on every invoice, what your bookkeeper reconciles against, what your reports run on. Adding 4,000 alias rows pollutes it for everyone. The cross-reference belongs in a separate store that doesn't touch the catalog at all.

What this looks like in SideQuest specifically

SideQuest stores the cross-reference table as a CSV file under ~/.qb-distributor-mcp/cross_reference.csv on your computer. Three columns: customer_qb_id, customer_pn, qb_sku. The file is plain text — you can edit it in Excel, version-control it with git, back it up however you back up the rest of your accounting files.

The matcher loads it at connector startup. Updates from the auto-learning loop append to it in real time. When you review a draft and confirm a customer-specific PN, the row writes immediately.

The table is never sent to our servers. We don't have it, we don't index it, we never see your customer-PN relationships. It lives entirely on your machine.

What to do this Saturday

If you're starting from a cold catalog and want to bootstrap the cross-reference table before processing live POs, the SKU mapping template has the CSV format and a starter spreadsheet. Most distributors can pre-populate 100-200 rows from their top 10 customers' recent POs in about 20 minutes. That alone moves the Day-1 match rate from ~70% to ~92% on those customers.

The remaining customers fill in via the auto-learning loop as their POs flow through. We wrote the full 20-minute Saturday recipe here.

Try the cross-reference logic on a real PO. The parser playground shows the matcher's candidate list and confidence breakdown for every line — same logic that runs in production. No signup, no upload, your PO content never leaves your browser.

Keep reading

SideQuest Automation · sidequestautomation.com
Questions? Send a brief