Corporate Structure
Retrieve and visualize the complete corporate hierarchy of any company, including all subsidiaries and parent relationships.
Interactive Demo
Try it yourself
Don't have an API key? Get your API key →
How It Works
The BoldData 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)
cURL Examples
# Search for a company
curl -G "https://app.companydata.com/api/company/search" \
-H "x-api-key: YOUR_API_KEY" \
-d "search=Shell"
# Get company details (to find Global Headquarter ID)
curl -G "https://app.companydata.com/api/company/export" \
-H "x-api-key: YOUR_API_KEY" \
-d "ID=407809109"
# Get all companies in the corporate group
curl -G "https://app.companydata.com/api/company/export" \
-H "x-api-key: YOUR_API_KEY" \
-d "worldwideHeadquarterID=407809109"