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:

  1. Search for your target company
  2. Get the Global Headquarter ID Number from the company record
  3. Fetch all companies in the group using worldwideHeadquarterID
  4. Group companies by their parent: Local HQ ID → National HQ ID → Global HQ ID
  5. Build a tree structure from the grouped results

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"

Was this page helpful?