Mid-Market P&L Variance Analysis: Data Inputs, Taxonomies, and What the Big Three ERPs Will Actually Give You
The question
What are the standard data inputs, formats, and variance category taxonomies that mid-market finance teams ($50M–$500M revenue) use for monthly P&L variance analysis, and how do NetSuite, Sage Intacct, and QuickBooks Enterprise export them?
Context: the ab-managerial-accounting brigade is under active build and MAC's client-reporting use case hinges on automating variance commentary. Source-system data shapes must be known before the brigade can be scoped against real deliverables.
What we already know (from the vault)
- The shipped variance-analysis skill encodes standard costing, not FP&A budget-vs-actual. [[cma-variance-core-competency]] is CMA Part 1 depth: static → sales-volume + flexible-budget, then DM price/quantity, DL rate/efficiency, VOH spending/efficiency, FOH budget/production-volume, plus mix and yield. Every one of those formulas needs quantities (units, hours, standard rates). None of that lives in a GL.
- The ticket is closed and shipped. variance-analysis-ticket shows the build completed 2026-06-28 (5/5 critic PASS), with the execution-eval showing all lift concentrated on the judgment fixture (Sonnet +33pp, Haiku +22pp, Opus 0). Artifacts live in
plugins/discipline-skills/skills/variance-analysis/in ray-plugins, merged in PR #6. The skill is real; its scope is manufacturing standard costing. - The buyer-side framing is already in the vault. [[2026-03-28-cfosecrets-unbundling-the-erp-tech-legacy-iv]] prescribes shrinking the ERP to GL + sub-ledgers and putting an AI-driven integration layer (Layer 3) and intelligence canvas (Layer 4) around it. Variance commentary automation is a Layer 4 product sitting on a Layer 3 problem.
- Practitioner standard for what "good" reporting looks like. [[2026-06-27-cfo-secrets-growth-cfo-iv-handbrake-off]] names it directly: "margin-level reporting (not averages), variance carve-ups separating growth-driven vs. execution-delayed variances, clean narrative storytelling." Warning sign: "discussing headlines instead of drivers."
- Allocations are a known landmine. [[2026-05-19-mostly-metrics-when-to-allocate-overhead]] covers when and what to push from G&A out to departments. Allocated cost lands on a department that never authorized the spend, which breaks naive owner-attribution in commentary.
What the web says
- Sage Intacct is the only one of the three with a native single-call budget-vs-actual-by-dimension API.
get_accountbalancesbydimensionstakes<contentselection>=Actual|Budget|Actual and Budget, plus<budgetid>and<budgetcomparison>=Budget minus Actual|Actual minus Budget.<groupby>accepts comma-separated dimensions:location,department,class,project,taskid,costtypeid,customer,vendor,employee,item,warehouse,contract, and user-defined dimensions. Periods come from<reportingperiodname>(e.g.Calendar Year Ended December 2016) or<startdate>/<enddate>with nested<year>/<month>/<day>. Response carries<glaccountno>,<startbalance>,<periodbalance>,<endbalance>,<budgetbalance>,<difference>,<currency>, and paired dimension id/name elements (<departmentid>/<departmentname>).readReportis the async wrapper for large result sets;readByQueryhits raw balance objects and requires aPERIOD = 'Month Ended June 2016'predicate (developer.intacct.com). It is an XML API, not REST. - NetSuite's documented extraction paths do not include a statement-shaped API. Oracle's own "Extracting Data from NetSuite" page lists exactly five: Full CSV Export (
Setup > Import/Export > Export Tasks), Saved Search export (CSV), Report export (CSV), SuiteTalk SOAP web services, and SuiteAnalytics Connect via ODBC/JDBC/ADO.NET. Oracle explicitly notes Report export is "more useful than saved searches for getting transaction information, since they provide easier matching of totals," and that ODBC access is an additional service with an associated fee (docs.oracle.com). Notably, that page does not mention SuiteQL or REST at all. - SuiteQL over REST exists but is a data-extraction tool, not a reporting tool. Secondary sources describe SuiteQL as SQL-like, faster and more flexible than saved searches, callable via
N/query, SuiteAnalytics Workbook, or the REST API; the guidance is to use Workbooks for financial statement visualization and SuiteQL for programmatic extraction (brokenrubik.com, kimberlitepartners.com). Practical consequence: via API you get transaction lines and the account master, and you rebuild the P&L rollup yourself. - QuickBooks Desktop returns a rendered report grid, not a data frame. qbXML
BudgetSummaryReportQueryexposes exactly five report types:BalanceSheetBudgetOverview,BalanceSheetBudgetVsActual,ProfitAndLossBudgetOverview,ProfitAndLossBudgetPerformance,ProfitAndLossBudgetVsActual.FiscalYearis a required element.BudgetCriterionisAccounts|AccountsAndClasses|AccountsAndCustomers(one dimension only, never both).SummarizeBudgetRowsBy=Account|Class|Customer;SummarizeBudgetColumnsBy=Class|Customer|Date. The responseReportRetcarriesNumRows,NumColumns,ColDesc(withcolID/dataTypeattrs), andReportDataas an unbounded choice ofDataRow|TextRow|SubtotalRow|TotalRow, whereRowDatahas arowTypeattribute (account,class,customer, …) andColDatacarriescolID/value/dataType(qbXML 13.0 schema,QBCqbxml130.xsd). - The load-bearing QuickBooks negative: there is no
ReportAccountFilterand noReportEntityFilteron the budget query. UnlikeGeneralDetailReportQuery, the only filter available isReportClassFilter. You cannot scope a budget-vs-actual pull by account or by customer/job. - IIF cannot export transactions. Intuit's own help article states IIF exports lists, and Intuit will not provide technical assistance for IIF (quickbooks.intuit.com). Desktop's budget wizard allows Customer:Job or Class, not both, which independently corroborates the
BudgetCriterionenum. - QuickBooks Online is a materially different product from Desktop Enterprise here. QBO v3 exposes a readable
Budgetentity withBudgetDetaillines carryingBudgetDate,Amount,AccountRef,CustomerRef,ClassRef,DepartmentRef(Location) — so dimensional budget lines are API-readable in QBO but must be grid-parsed in Desktop. QBO has a documentedProfitAndLossDetailreport endpoint but no documentedBudgetVsActualsendpoint, and the Reports API hard-caps at 400,000 cells per response. Usage limits: QBO Plus allows 40 classes+locations combined; Advanced is unlimited. - UI export formats carry their own trap. Sage guidance recommends CSV over Excel export because Intacct exports XLS (not XLSX), which caps at 65,536 rows.
Convergences and contradictions
- Convergence: the CFO Secrets unbundled-ERP thesis ([[2026-03-28-cfosecrets-unbundling-the-erp-tech-legacy-iv]]) predicted exactly the pattern the vendor docs confirm. The ERP is good at being a GL and sub-ledger and bad at being a reporting surface; all three vendors expose balances well and statements poorly. The Layer 3 integration layer is not optional architecture-astronautics, it is the literal gap between
get_accountbalancesbydimensionsand a P&L a CFO will read. - Contradiction, and it is the important one: the vault's variance competency ([[cma-variance-core-competency]]) is a standard-costing taxonomy whose inputs (AQ purchased, AH, SH allowed, standard rates) do not exist in any of the three exports surveyed. Every export path above returns dollars by account by dimension by period. The shipped skill and the MAC client-reporting use case are solving different problems. Nothing in the ticket flagged this, because the ticket was scoped from a CMA knowledge source rather than from a client data shape.
- Partial contradiction on NetSuite: Oracle's canonical extraction page omits SuiteQL and REST entirely, while the practitioner web treats SuiteQL-over-REST as the default modern answer. The docs page is likely stale rather than wrong. Treat SuiteQL as available but verify against a live account before it becomes a scoping assumption.
Synthesis for RDCO
The taxonomy the brigade needs is not the taxonomy it built. Mid-market monthly variance analysis runs on a comparison-basis grid crossed with a cause-category vocabulary, not on standard-cost decomposition. The comparison bases are four, each computed MTD and YTD, each as both dollar and percent: actual vs budget (original annual plan), actual vs latest forecast/outlook, actual vs prior period, actual vs prior year same period. The cause categories that show up in real commentary are volume, rate/price, mix, timing/phasing (spend slipped a month), one-time vs run-rate, headcount-driven (headcount × rate), accrual true-up or release, reclass/mapping change, allocation change, and FX (translation vs transaction). Standard costing shows up only for the subset of clients who manufacture. The correct move is not to rewrite the shipped skill but to add a sibling skill for FP&A budget-vs-actual commentary and let the brigade's use-case menu route between them. The shipped skill stays valid for the manufacturing ICP.
On automatability, the three vendors are not one tier, they are three. Sage Intacct is genuinely automatable end to end: one call to get_accountbalancesbydimensions with contentselection = Actual and Budget returns actual, budget, and difference grouped by any dimension combination, with readReport handling volume. NetSuite is automatable with real work: the API gives you transaction lines and the account master, so the brigade must reconstruct statement structure, sign conventions, and rollups itself, or the client must pay for SuiteAnalytics Connect (a licensed add-on, so it is a commercial gate not just a technical one). QuickBooks Desktop Enterprise should be scoped as human-export-step for v1: the qbXML path requires an on-prem Windows connector, returns a presentation grid whose hierarchy must be inferred from rowType and subtotal placement, and cannot filter by account at all. Quoting a QuickBooks Enterprise client the same automated-ingestion SLA as an Intacct client would be a mistake, and the difference is worth pricing differently.
The build should target a canonical intermediate schema, and the adapters should be the disposable part. Something on the order of period, entity, account_id, account_name, account_path, statement_section, department, class, location, project, scenario, amount, currency — where scenario ∈ {actual, budget, forecast, prior} — lets the variance engine, the materiality gate, and the commentary generator be written once against a stable shape. This is a plain data-engineering move and it is squarely the founder's muscle, which makes it a credible MAC content cluster as well as a build decision. Account hierarchy handling differs enough per vendor to justify the abstraction on its own: Intacct treats account groups as a first-class reporting-structure object, NetSuite uses parent-child plus summary accounts on the account record, and QuickBooks nests sub-accounts. Typical mid-market depth is three to five levels over roughly 200–800 GL accounts.
Where the joins get ugly is where the engagement risk lives, and it should be surfaced in scoping, not discovered in delivery. The most common hard blocker is budget grain below actual grain: budgets are frequently loaded at department level only while actuals post at department + class + location + project, which makes sub-department variance mathematically undefined. Close behind is that for most mid-market teams the budget does not live in the ERP at all — it lives in Excel or a planning tool, meaning the budget adapter is a separate integration from the actuals adapter every time. Then: nullable dimensions on top-side adjustments and accruals producing an "Unassigned" bucket that no owner will claim; intercompany eliminations, where consolidated P&L is not the sum of entity P&Ls and elimination entries land on a plug entity; allocation JEs that post after the first close draft, so variance run timing changes the answer; FX, where a variance in reporting currency can be entirely translation with zero local-currency movement; mid-year account reclasses that silently corrupt prior-period comparison because none of these systems export effective-dated COA history cleanly; and 4-4-5 or 13-period fiscal calendars, which is why Intacct's reportingperiodname is a named-period string rather than a date range. Finally, sign convention: favorable/unfavorable flips by account type, NetSuite stores credits negative on transaction lines while reporting revenue positive, and QuickBooks pre-signs values for display. Getting F/U backwards on a client deliverable is the single most embarrassing available failure, and it is a one-line bug.
Why this is in the vault
This brief is the input that lets the ab-managerial-accounting brigade be scoped against a real client deliverable instead of against a textbook: it establishes that the already-shipped variance-analysis skill (variance-analysis-ticket, merged PR #6) solves standard costing while MAC's client-reporting use case needs FP&A budget-vs-actual commentary, and it supplies the vendor-by-vendor automatability tiering (Intacct automatable, NetSuite reconstructable, QuickBooks Enterprise human-export) that should drive both the adapter build order and differential pricing per client ERP.
Open follow-ups
- What is the actual materiality-threshold convention mid-market controllers use to decide which lines get written commentary — dual dollar-and-percent gates, and at what typical values by revenue band? This directly sets the volume of commentary the brigade must generate per close.
- Confirm against a live NetSuite account whether SuiteQL over REST can return budget records joined to actuals, and what the practical row/timeout ceiling is. Oracle's own extraction docs omit SuiteQL entirely.
- Does the QuickBooks Desktop company file need to be open, in single-user mode, on an interactive Windows session for the Web Connector to serve qbXML? Only vendor/secondary sources assert this; no Intuit primary source found. It determines whether QBE ingestion can be unattended at all.
- Which planning tools (Vena, Planful, Pigment, Abacum, Cube, Datarails, Mosaic) hold the budget for the mid-market segment, and which expose a budget-version API? If the budget adapter is always a second integration, this is half the build.
- What does a defensible "cite your evidence" constraint look like for generated variance commentary — journal-entry-level drill-down, vendor/memo extraction? The number is trivial; the why is where hallucination risk concentrates.
- How do Intacct account groups, NetSuite summary accounts, and QuickBooks sub-account nesting map onto one canonical
account_path, and does any of them export effective-dated COA history for clean prior-period restatement?
Related
- [[cma-variance-core-competency]] — the standard-costing taxonomy the shipped skill encodes; the contrast case for this brief
- variance-analysis-ticket — the closed brigade ticket whose scope this brief re-frames
- [[variance-worked-examples]] — golden fixtures; the oracle source for any FP&A sibling skill
- [[variance-interpretation-and-pitfalls]] — domain-fidelity and no-slop guards, directly reusable for commentary generation
- [[2026-03-28-cfosecrets-unbundling-the-erp-tech-legacy-iv]] — the 4-layer stack; this brief is the Layer 3 detail underneath it
- [[2026-06-27-cfo-secrets-growth-cfo-iv-handbrake-off]] — practitioner standard for variance carve-ups and narrative reporting
- [[2026-05-19-mostly-metrics-when-to-allocate-overhead]] — allocation mechanics, one of the named ugly joins
- [[2026-04-28-cfosecrets-finance-stack-of-the-future-unbundled-erp]] — companion unbundled-ERP framing
Sources
Vault
~/rdco-vault/10-source-material/competencies/variance-analysis/cma-variance-core-competency.md~/rdco-vault/10-source-material/competencies/variance-analysis/variance-worked-examples.md~/rdco-vault/10-source-material/competencies/variance-analysis/variance-interpretation-and-pitfalls.md~/rdco-vault/08-tooling/brigade-rail/variance-analysis-ticket.md~/rdco-vault/06-reference/2026-03-28-cfosecrets-unbundling-the-erp-tech-legacy-iv.md~/rdco-vault/06-reference/2026-06-27-cfo-secrets-growth-cfo-iv-handbrake-off.md~/rdco-vault/06-reference/2026-05-19-mostly-metrics-when-to-allocate-overhead.md
Web
- Sage Intacct Developer — Account Balances: https://developer.intacct.com/api/general-ledger/account-balances/
- Sage Intacct Developer — Trial Balances: https://developer.intacct.com/api/general-ledger/trial-balances/
- Sage Intacct Developer — Budgets: https://developer.intacct.com/api/general-ledger/budgets/
- Oracle NetSuite — Extracting Data from NetSuite: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_N464759.html
- Oracle NetSuite — Exporting Search Results: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_N663983.html
- SuiteQL Complete Guide (BrokenRubik): https://www.brokenrubik.com/blog/suiteql-complete-guide
- SuiteAnalytics vs Saved Searches (Kimberlite Partners): https://www.kimberlitepartners.com/blog/suiteanalytics-vs-saved-searches
- Intuit Developer — BudgetSummaryReportQuery: https://developer.intuit.com/app/developer/qbdesktop/docs/api-reference/qbdesktop/budgetsummaryreportquery
- qbXML 13.0 schema (
QBCqbxml130.xsd), Intuit-shipped, mirrored: https://raw.githubusercontent.com/johnballantyne/qbxml/master/lib/xsd/QBCqbxml130.xsd - Intuit — Export, import, and edit IIF files: https://quickbooks.intuit.com/learn-support/en-us/help-article/import-export-data-files/export-import-edit-iif-files/L56LT9Z0Q_US_en_US
- Intuit — Create a budget or forecast in QuickBooks Desktop: https://quickbooks.intuit.com/learn-support/en-us/help-article/financial-reports/create-budget-forecast-quickbooks-desktop/L4bHm1wBM_US_en_US
- Intuit — QuickBooks Online usage limits: https://quickbooks.intuit.com/learn-support/en-us/help-article/intuit-subscriptions/learn-usage-limits-quickbooks-online/L6THMltE4_US_en_US
- Intuit Developer Blog — QuickBooks Online Reports API best practices (400k cell limit): https://medium.com/intuitdev/quickbooks-online-reports-api-best-practices-and-troubleshooting-31edc9934b4c
- Intuit — ProfitAndLossDetail report entity: https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/profitandlossdetail
Verification note: QuickBooks Desktop connector operational requirements (company file open, single-user mode, interactive Windows session) and the absence of a cloud-callable REST API for QuickBooks Desktop Enterprise could not be confirmed from an Intuit primary source and are carried as unverified. NetSuite SuiteQL/REST capability is secondary-sourced only; Oracle's canonical extraction page does not mention it.