What went in
Two documents, both published by the vendors themselves, both used as-is:
- Source — Intuit’s QuickBooks Online Accounting API reference for the Customer entity: 42 fields with types, requiredness and descriptions.
- Target — NetSuite’s public SuiteTalk schema for the Customer record: 139 fields, taken straight from the XSD.
Both files were read in full — no truncation, nothing dropped. That matters, because a mapping drafted from part of a spec that presents itself as a mapping of the spec is the first way this kind of tool lies to you.

What came out
Of the 139 NetSuite customer fields, the run proposed a source for 29 and abstained on 110, raising 21 questions along the way — nine of them serious enough to stop on, covering eight distinct problems. The abstentions are not a shortfall. QuickBooks Online has no credit limit, no sales rep, no territory, no subsidiary, no partner-and-campaign lineage; a tool that returned 139 confident rows here would have invented 110 of them.

The 29 it proposed
Unedited and in export order. Confidence is the model’s own self-assessment — a cue for what to read first, never a verification. The evidence underneath it is the proof.
| QuickBooks Online | NetSuite | Type | Confidence |
|---|---|---|---|
| DisplayName | altName | direct | high |
| AlternatePhone | altPhone | transformation | high |
| Notes | comments | direct | high |
| CompanyName | companyName | direct | high |
| CurrencyRef | currency | lookup | high |
| PrimaryEmailAddr | transformation | high | |
| Id | externalId | direct | high |
| Fax | fax | transformation | high |
| GivenName | firstName | direct | high |
| — | internalId | generated | high |
| Active | isInactive | conditional | high |
| FamilyName | lastName | direct | high |
| MiddleName | middleName | direct | high |
| Mobile | mobilePhone | transformation | high |
| Balance | openingBalance | direct | high |
| OpenBalanceDate | openingBalanceDate | transformation | high |
| ParentRef | parent | lookup | high |
| PrimaryPhone | phone | transformation | high |
| PrintOnCheckName | printOnCheckAs | direct | high |
| ResaleNum | resaleNumber | direct | high |
| Title | salutation | direct | high |
| Taxable | taxable | direct | high |
| Taxable | taxExempt | conditional | high |
| SalesTermRef | terms | lookup | high |
| BillAddr + ShipAddr | addressbookList | transformation | medium |
| PreferredDeliveryMethod | emailTransactions | conditional | medium |
| PreferredDeliveryMethod | printTransactions | conditional | medium |
| DefaultTaxCodeRef | taxItem | lookup | medium |
| WebAddr | url | transformation | medium |
Three rows worth reading closely
A straight CompanyName → companyName needs no justification. A derived rule does, so those rows carry the verbatim line from the spec they rest on.
CASE WHEN Active IS NULL THEN NULL ELSE NOT Active END
NetSuite inactivity is the logical inverse of QBO's enabled-for-use indicator.
“If true, this entity is currently enabled for use by QuickBooks.” — QuickBooks Online, Active
A polarity flip. Copy this one straight across and every active customer arrives in NetSuite switched off — and the quote is what lets a reviewer confirm the inversion in two seconds instead of trusting it.
Lookup NetSuite Customer where externalId = ParentRef.value; return its RecordRef
QBO ParentRef identifies the immediate parent, and the parent can be resolved through the migrated QBO external identifier.
“A reference to a Customer object that is the immediate parent of the Sub-Customer/Job in the hierarchical Customer:Job list.” — QuickBooks Online, ParentRef
It didn’t just pair two fields — it worked out that the parent has to be resolved through the external ID the migration itself writes, which constrains the load order.
Assigned by NetSuite when the Customer record is created
No source field applies: the target system produces this value itself.
No quote on this row — it makes no claim about the source document, so there is no passage to cite.
Not every unmapped field is a gap. This one has no source because it can’t have one, and saying so is different from shrugging.
The eight it stopped on
Nine blocker-severity questions came out of the run, covering eight distinct problems — the subsidiary one was flagged independently in both the field and the mapping phase. If you have done this migration, you have had these exact arguments:
- Which NetSuite subsidiary should receive migrated customers? (raised in both phases)
- Which QBO value should become the NetSuite Customer entityId?
- What rule should determine NetSuite isPerson?
- Which QBO address, if any, should populate NetSuite defaultAddress?
- How should QBO tax identifiers be migrated given that API responses mask them?
- How will customer receivables balances be migrated?
- Which NetSuite account should be used for openingBalanceAccount when opening balances are loaded?
- How should BillAddr and ShipAddr be represented in NetSuite addressbookList?
None of these can be answered from the two specs, which is precisely why they are questions and not mappings. The subsidiary one alone decides whether the load runs at all.
What this does not show
- It is not a reviewed workbook. This is raw output. A real deliverable has a human decision on every row; that step is the product, and it hasn’t been done here.
- The 29 are not verified correct. They are proposals with their evidence attached so you can check them quickly. At least one — url — carries an explicit assumption that the exact emitted property needs confirming.
- Your specs are messier than these. Vendor API references are unusually clean. A client’s half-finished requirements sheet will produce more questions, not fewer.
- It maps the spec, not your data. Nothing here touched a customer record, and nothing moves anything: Crossary produces the design a developer then implements.