Multi-entity accounting and tracking dimensions
This guide explains how Apideck's Accounting API handles multiple companies or legal entities and tracking dimensions (departments, locations, subsidiaries, and custom categories). Understanding both helps you build integrations that match how each accounting platform works.
Why this matters
Accounting systems differ in how they separate data:
- Some treat each legal entity as a fully isolated dataset (separate chart of accounts, journals, and invoices).
- Others use one connection for many entities and expect you to tag each transaction with a subsidiary or similar dimension.
- Dimensions (department, location, class, project, etc.) add reporting slices on top of that—often per line on an invoice or journal.
If you mix up "which entity's data am I reading?" with "how is this line tagged for reporting?", filters and writes can behave in ways that look inconsistent. This guide separates those two ideas clearly.
Two layers: data scope vs tagging
Layer 1 — Data boundary (which entity's books?)
This answers: When I list ledger accounts, invoices, or journal entries, whose data am I seeing?
For connectors that support per-request company switching, you choose the entity by sending the x-apideck-company-id HTTP header on Accounting API requests. The value is an identifier returned by GET /accounting/companies for that connection.
If you omit the header, requests typically use the default company stored on the connection (for example, the organisation or entity chosen during setup or OAuth).
Layer 2 — Tracking dimensions (how is this transaction segmented?)
This answers: How should this invoice or line appear in management reporting—by department, location, legal entity tag, or custom category?
Common fields on transaction headers and line items:
| Concept | API fields (typical) | Role |
|---|---|---|
| Department | department_id | Cost center / org unit |
| Location | location_id | Site, region, or logical place |
| Subsidiary | subsidiary_id | Legal entity tag on the transaction |
| Custom segments | tracking_categories[] | Classes, projects, grants—platform-dependent |
Note
For most connectors, department, location, and tracking categories are tags for reporting. They do not by themselves switch which company's list endpoints return.
Subsidiary is special: it often acts as a dimension on the transaction, and on some platforms it is tightly tied to which legal entity owns that transaction. It is still distinct from the x-apideck-company-id header, which controls read scope where that feature is supported.
How the two layers work together
When both apply, you might scope reads to Company A with the header, while line items still carry their own department_id, location_id, or tracking_categories. Line-level dimension values usually override header-level values for that line—useful when one document splits costs across teams or projects.
Switching companies with x-apideck-company-id
What to do
Step 1 — List available companies:
Step 2 — Use a company ID on subsequent requests:
This returns invoices for Acme UK Ltd. only. Same connection, same consumer—just a different company context.
Note
Connection metadata may also expose a default company identifier (for example in connection metadata after setup). The header overrides that default when the connector supports multi-company switching.
Virtual Webhooks limitation
Virtual Webhooks currently only sync data from the default company configured during connection setup. The x-apideck-company-id header is not supported for webhook subscriptions. If you need events from multiple companies, either create separate connections per company or poll the API with the header on a schedule.
Which pattern does your connector use?
Use this decision tree to determine the right approach:
Connectors that support per-request company switching
| Connector | What "company" represents | Downstream mechanism |
|---|---|---|
| Xero | Organisation | Xero-Tenant-Id header |
| Sage Intacct | Entity | Session follows selected entity |
| Sage Business Cloud | Business | Business context switch |
| Dynamics 365 BC | Company | Company in URL path |
| Exact Online | Division | Division-based routing |
Exact Online variants
Choose the service_id that matches your product—exact-online, exact-online-nl, or exact-online-uk. All three use the same division-based pattern for GET /accounting/companies and x-apideck-company-id.
Always confirm current behavior in the Apideck Accounting API reference for your connector; capabilities evolve.
Connectors that need one connection per company
Some integrations bind one OAuth token (or one company) to a single legal entity. In those cases x-apideck-company-id does not switch companies—you create one connection per company.
- QuickBooks Online — One company per connection (realm)
- MYOB — One company per connection
Other connectors (not in the header-switching table)
Many other accounting service_id values follow different rules:
| Pattern | What to expect | Examples |
|---|---|---|
| One ledger per connection | Use another Vault connection for another company | FreshBooks, Zoho Books, KashFlow, FreeAgent, Banqup, Visma Netvisor, Procountor, Access Financials |
| Entity on records | Entity may appear on payloads or query parameters | Campfire, Dualentry |
| Rich dimensions, scoped connection | One company per connection; dimensions are fields | Acumatica, MYOB-Acumatica |
| Enterprise dimensions | company_id / subsidiary_id / worktags carry entity meaning | Intuit Enterprise Suite, Workday |
For any connector, confirm multi-company flags, required fields, and resource coverage in the Accounting API reference and the connector's page on developers.apideck.com/connectors.
Xero: multiple organisations vs app partnership
These are two separate ideas:
If you are scaling to many end-customer connections, plan for Xero's commercial and certification requirements in addition to multi-org switching. See Xero's App Partner program, Apideck's Xero connector documentation, and Xero API pricing and the App Partner Program.
Does the parent GL include subsidiaries? (Roll-up behavior)
A common question when integrating with multi-entity ERPs: when I read GL data at the parent level, do I get a roll-up of all subsidiaries, or just the parent's own ledger?
This depends entirely on how the downstream ERP returns data. Apideck does not aggregate or consolidate — it returns what the ERP gives.
Note
For roll-up systems, there is no separate "parent-only" ledger — the parent is the sum of the parts. If you need individual entity views, filter the response by the subsidiary or entity field. If you need a consolidated view, the rolled-up response already contains all entities, but you may still need to handle intercompany elimination and currency conversion in your application.
What this means for your integration:
| If the ERP... | Then to show one entity's GL... | And to show a consolidated GL... |
|---|---|---|
| Rolls up (NetSuite, Workday, Acumatica) | Filter the response by subsidiary_id or equivalent | Use the full response, then eliminate intercompany + convert currencies |
| Isolates (Xero, QBO, Exact, Dynamics BC) | Just read — the response is already scoped | Iterate all entities, merge, eliminate intercompany + convert currencies |
| Configurable (Sage Intacct) | Use entity-scoped session via x-apideck-company-id | Either use top-level session for rolled-up data, or iterate entities |
NetSuite (OneWorld) — important nuance
NetSuite often exposes all subsidiaries through a single connection. Many transactions require a subsidiary (especially in OneWorld).
NetSuite field overlap
On reads, NetSuite frequently populates company_id from the same subsidiary metadata. On some resources (vendors, purchase orders), company_id and subsidiary_id appear with the same value. On others, only company_id is set while subsidiary_id is empty. Checks are an exception: company_id may reflect a different NetSuite field than line-level subsidiary_id—do not assume they always match.
For deeper product context, see: Tracking dimensions in accounting integrations.
Tracking dimensions — quick reference
Master data endpoints
Where dimensions appear on transactions
Support varies by resource and by connector. At the unified API level, several resources accept department_id, location_id, subsidiary_id, and/or tracking_categories on the header and/or line items—not always all four on every resource.
Typical patterns by resource:
| Resource | Header dimensions | Line-item dimensions |
|---|---|---|
| Invoices & bills | department, location, tracking categories | All four including subsidiary |
| Journal entries | Varies | Primarily on lines |
| Credit notes | department, location | Often fewer subsidiary fields than invoices |
Refer to the request body schema for each operation in the API reference for the exact combination.
How popular platforms map to unified fields
Note
Xero has no separate department/location/subsidiary resources. Many customers use their two tracking categories to represent "department" and "region." Workday uses worktags for most dimensions—company_id and subsidiary_id behave differently there.
company_id vs subsidiary_id on transaction records
The unified API exposes both company_id and subsidiary_id in places, but connectors treat them differently:
Note
For legal-entity tagging on create/update, prefer subsidiary_id unless documentation for your connector explicitly requires company_id.
Frequently asked questions
How do I read GL data for one specific entity?
What is the difference between x-apideck-company-id and subsidiary_id?
They may align for a given document (same entity everywhere) or differ in advanced cases (for example intercompany entries where lines reference different entities).
Should I use company_id or subsidiary_id on create/update payloads?
Prefer subsidiary_id for legal-entity tagging on transactions.
| Connector | Recommendation |
|---|---|
| NetSuite | company_id often mirrors subsidiary_id (same value). Pick one consistent field after checking the response shape per resource. |
| Workday | Not interchangeable — use what the resource schema specifies. |
| Others | company_id is easily confused with connection settings or the header. Default to subsidiary_id. |
How do I consolidate GL data across entities for one customer?
This is application-level logic — Apideck provides the per-entity data, your platform handles mapping, conversion, and elimination.
Can one API call represent multiple legal entities?
That is intercompany or cross-entity posting. It is only possible where the downstream system allows it. NetSuite and Workday are common examples; many SMB-oriented systems isolate entities per connection or per organisation.
Consolidating GL data across entities
A common use case is reading GL data from multiple legal entities and merging it into a single view — for consolidated reporting, intercompany elimination, or multi-entity dashboards. This section explains how entity data maps to Apideck's consumer model and what to consider when designing consolidation logic.
How entities map to consumers and connections
In Apideck, a consumer represents your customer. One consumer can have multiple connections, and some connections give access to multiple companies. Understanding this hierarchy is key to consolidation:
All five entities belong to one consumer (acme-corp). To build a consolidated view you need to iterate across all of them — some via the header, some via separate connections.
Reading GL data across all entities
Example: iterating entities for one consumer
Header-switching connector (e.g. Xero):
Connection-per-company connector (e.g. QuickBooks):
Key considerations for consolidation
Charts of accounts differ per entity
Each legal entity may have its own chart of accounts with different account numbers, names, and structures. Your consolidation logic needs a mapping layer:
See the Ledger Account Mapping guide for how to build a mapping interface.
Currency handling
Multi-entity setups often span currencies. The Accounting API returns amounts in each entity's base currency. Your consolidation must:
- Identify each entity's base currency (from company or ledger account metadata)
- Apply exchange rates to convert to your reporting currency
- Handle exchange rate differences as a separate consolidation line
Intercompany elimination
When entities transact with each other (e.g. Acme US invoices Acme UK), those balances appear in both entities' books. For a true consolidated view, you need to:
- Identify intercompany transactions (by counterparty, tracking category, or a naming convention)
- Eliminate matching receivables/payables so they do not double-count
Note
Apideck does not perform consolidation, currency conversion, or intercompany elimination — these are application-level responsibilities. The API provides the per-entity data you need to build these workflows.
NetSuite consolidation specifics
NetSuite OneWorld returns data across subsidiaries in a single response. For consolidation:
Unlike isolated connectors (Xero, QBO, Dynamics BC) where each API call returns one entity's data, with NetSuite you receive mixed data and must group by subsidiary_id yourself.
Roll-up ERPs vs isolated ERPs — consolidation strategy
Current limitations (good to plan for)
- NetSuite — List endpoints may aggregate across subsidiaries; do not assume header-based scoping behaves like Xero or Sage Intacct.
company_id/subsidiary_idduplication varies by resource; checks may not follow the same pattern as invoices or vendors. company_idvssubsidiary_id— Redundant same-value pairs are primarily a NetSuite quirk. Workday intentionally uses both fields differently. Most SMB connectors scope company via connection or headers, not both body fields.- Sage Intacct — Entity and location concepts can overlap.
company_idin settings is for auth/session, not dimension tagging. - Connector matrix — Not every connector exposes all four dimension types or CRUD for every dimension resource; always check the connector's Accounting coverage.
- Connectors omitted from examples — Regional variants, niche ERPs, and new connectors may differ; treat the API reference as the source of truth when this guide does not name your
service_id.
Related resources
If you need a connector-specific implementation checklist (auth, required fields, sandbox), use Apideck's connection and connector guides for that service in the developer portal.