Corporate Structure
Map parent companies, subsidiaries, branches, and UBO charts for any group in 200+ countries using HQ ID fields from official registers (not inferred website data). Export one record to read Global Headquarter ID Number, then pass it as worldwideHeadquarterID on /api/company/export to retrieve every entity in the corporate group in one query.
Interactive Demo
Try it yourself
Don't have an API key? Get your API key →
How It Works
The CompanyData API provides ID fields that define a company's position in its corporate hierarchy:
- Global Headquarter ID Number - The ultimate parent of the entire corporate group
- National Headquarter ID Number - The highest parent within the same country
- Local Headquarter ID Number - The immediate parent entity
- worldwideHeadquarterID - Query parameter to fetch all companies in a group
The approach:
- Search for your target company
- Get the
Global Headquarter ID Numberfrom the company record - Fetch all companies in the group using
worldwideHeadquarterID - Group companies by their parent: Local HQ ID → National HQ ID → Global HQ ID
- Build a tree structure from the grouped results
For large corporations like Shell or BP, this may return thousands of companies. The demo limits results with a maxCompanies parameter.
Implementation
The code below powers the interactive demo above. Copy and adapt it for your own use.
Types
interface Company {
ID: string
'Company Name': string
'Country Code'?: string
'Country Name'?: string
'City'?: string
'Local Headquarter ID Number'?: string
'National Headquarter ID Number'?: string
'Global Headquarter ID Number'?: string
[key: string]: any
}
interface ApiResponse {
data: {
records: Company[]
totalCount?: number
}
}
interface CorporateTreeNode {
company: Company
subsidiaries: CorporateTreeNode[]
}
API Helper
const BASE_URL = 'https://app.companydata.com/api/company'
async function fetchApi<T>(apiKey: string, endpoint: string, params: Record<string, string | number>): Promise<T> {
const url = new URL(`${BASE_URL}/${endpoint}`)
Object.entries(params).forEach(([key, value]) => {
url.searchParams.append(key, String(value))
})
const response = await fetch(url.toString(), {
headers: { 'x-api-key': apiKey },
})
if (!response.ok) {
const text = await response.text()
throw new Error(`HTTP ${response.status}: ${text}`)
}
return response.json()
}
Search for Companies
async function searchCompany(apiKey: string, searchTerm: string): Promise<Company[]> {
const response = await fetchApi<ApiResponse>(apiKey, 'search', {
search: searchTerm,
page: 1,
pageSize: 25,
})
return response.data?.records ?? []
}
Get All Companies in Group
Fetch all companies belonging to the same corporate group in a single query:
async function getAllCompaniesInGroup(
apiKey: string,
globalUltimateId: string,
maxCompanies = 500
): Promise<Company[]> {
const allCompanies: Company[] = []
let page = 1
const pageSize = 50
let hasMore = true
while (hasMore && allCompanies.length < maxCompanies) {
const response = await fetchApi<ApiResponse>(apiKey, 'export', {
worldwideHeadquarterID: globalUltimateId,
page,
pageSize,
})
const records = response.data?.records ?? []
allCompanies.push(...records)
hasMore = records.length === pageSize && allCompanies.length < maxCompanies
page++
}
return allCompanies.slice(0, maxCompanies)
}
async function getCompanyById(apiKey: string, companyId: string): Promise<Company | null> {
const response = await fetchApi<ApiResponse>(apiKey, 'export', {
ID: companyId,
page: 1,
pageSize: 1,
})
return response.data?.records?.[0] ?? null
}
Build the Corporate Tree
Group companies by their parent HQ ID to build a tree structure:
function buildTreeFromFlatList(
companies: Company[],
rootCompany: Company
): CorporateTreeNode {
const globalUltimateId = rootCompany.ID
// Create a map of ID -> node for quick lookup
const companyMap = new Map<string, CorporateTreeNode>()
companies.forEach(company => {
companyMap.set(company.ID, { company, subsidiaries: [] })
})
// Use root from map if present, otherwise create from passed rootCompany
let root = companyMap.get(globalUltimateId)
if (!root) {
root = { company: rootCompany, subsidiaries: [] }
}
// Group companies by their parent ID
companies.forEach(company => {
if (company.ID === globalUltimateId) return // Skip the root
const node = companyMap.get(company.ID)
if (!node) return
const localHqId = company['Local Headquarter ID Number']
const nationalHqId = company['National Headquarter ID Number']
const globalHqId = company['Global Headquarter ID Number']
let parentId: string | null = null
// Local HQ is normally the parent. If that company is missing, fallback to National, then Global
if (localHqId && localHqId !== company.ID && companyMap.has(localHqId)) {
parentId = localHqId
}
else if (nationalHqId && nationalHqId !== company.ID && companyMap.has(nationalHqId)) {
parentId = nationalHqId
}
else if (globalHqId && globalHqId !== company.ID) {
parentId = globalHqId
}
if (parentId) {
const parent = companyMap.get(parentId) ?? root
parent.subsidiaries.push(node)
}
})
return root
}
Full Example
Putting it all together:
async function getCorporateStructure(
apiKey: string,
searchTerm: string,
maxCompanies = 500
): Promise<CorporateTreeNode | null> {
// Step 1: Search for the company
const companies = await searchCompany(apiKey, searchTerm)
if (!companies.length) {
console.log('No companies found')
return null
}
// Step 2: Get full company details
const fullCompany = await getCompanyById(apiKey, companies[0].ID)
if (!fullCompany) return null
// Step 3: Get Global Ultimate ID
const globalUltimateId = fullCompany['Global Headquarter ID Number']
if (!globalUltimateId) {
// Standalone company with no parent
return { company: fullCompany, subsidiaries: [] }
}
// Step 4: Fetch all companies in the group
const allCompanies = await getAllCompaniesInGroup(apiKey, globalUltimateId, maxCompanies)
// Step 5: Find or fetch the root company
let rootCompany = allCompanies.find(c => c.ID === globalUltimateId)
if (!rootCompany) {
rootCompany = await getCompanyById(apiKey, globalUltimateId)
}
if (!rootCompany) return null
// Step 6: Build tree by grouping under HQ IDs
return buildTreeFromFlatList(allCompanies, rootCompany)
}
// Usage
const tree = await getCorporateStructure('YOUR_API_KEY', 'Shell', 500)
Display the Tree
function printTree(node: CorporateTreeNode, indent = 0): void {
const prefix = ' '.repeat(indent)
const company = node.company
const location = [company['City'], company['Country Code'] ?? company['Country Name']].filter(Boolean).join(', ')
console.log(`${prefix}├── ${company['Company Name']}${location ? ` (${location})` : ''}`)
for (const subsidiary of node.subsidiaries) {
printTree(subsidiary, indent + 1)
}
}
// Output:
// ├── Shell plc (London, GB)
// ├── Shell Petroleum N.V. (The Hague, NL)
// ├── Shell Nederland B.V. (The Hague, NL)
// ├── Shell Deutschland GmbH (Hamburg, DE)
// ├── Shell Oil Company (Houston, US)
Request & Response Examples
Complete, copy-pasteable examples for the three-step corporate structure workflow.
1. Search for a company
curl -G "https://app.companydata.com/api/company/search" \
-H "x-api-key: YOUR_API_KEY" \
--data-urlencode "search=Shell" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=25"
Response:
{
"data": {
"records": [
{
"ID": "407809109",
"Company Name": "Shell plc",
"Country": "United Kingdom",
"City": "LONDON"
},
{
"ID": "407809110",
"Company Name": "Shell Nederland B.V.",
"Country": "Netherlands",
"City": "THE HAGUE"
}
],
"totalCount": 42
},
"page": 1,
"pageSize": 25,
"totalPages": 2
}
2. Export company details (find Global Headquarter ID)
curl -G "https://app.companydata.com/api/company/export" \
-H "x-api-key: YOUR_API_KEY" \
--data-urlencode "export=true" \
--data-urlencode "ID=407809109"
Response:
{
"data": {
"records": [
{
"ID": "407809109",
"Company Name": "Shell plc",
"City": "LONDON",
"Country": "United Kingdom",
"Location Type": "1",
"Subsidiary Code": "0",
"Global Headquarter ID Number": "407809109",
"Global Headquarter Company Name": "Shell plc",
"Number of Companies in Group": "2847"
}
],
"totalCount": 1
},
"page": 1,
"pageSize": 25,
"totalPages": 1
}
Copy Global Headquarter ID Number (407809109) for the next step.
3. Fetch all companies in the corporate group
curl -G "https://app.companydata.com/api/company/export" \
-H "x-api-key: YOUR_API_KEY" \
--data-urlencode "export=true" \
--data-urlencode "worldwideHeadquarterID=407809109" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=50"
Response:
{
"data": {
"records": [
{
"ID": "407809109",
"Company Name": "Shell plc",
"City": "LONDON",
"Country": "United Kingdom",
"Location Type": "1",
"Subsidiary Code": "0",
"Global Headquarter ID Number": "407809109",
"Global Headquarter Company Name": "Shell plc",
"Number of Companies in Group": "2847"
},
{
"ID": "407809110",
"Company Name": "Shell Nederland B.V.",
"City": "THE HAGUE",
"Country": "Netherlands",
"Location Type": "3",
"Subsidiary Code": "3",
"Local Headquarter ID Number": "407809109",
"Local Headquarter Company Name": "Shell plc",
"National Headquarter ID Number": "407809109",
"National Headquarter Company Name": "Shell plc",
"Global Headquarter ID Number": "407809109",
"Global Headquarter Company Name": "Shell plc",
"Number of Companies in Group": "2847"
}
],
"totalCount": 2847
},
"page": 1,
"pageSize": 50,
"totalPages": 57
}
Paginate through all pages (or use scroll pagination for large groups) and build a tree using Local Headquarter ID Number → National Headquarter ID Number → Global Headquarter ID Number. See the Response Fields reference for all hierarchy field definitions.