# LEI Lookup & Corporate Ownership Tree, from GLEIF data (`br_data_hub/lei-corporate-tree`) Actor

Look up companies by LEI or name in GLEIF's open Global LEI Index: legal data, direct and ultimate parent, subsidiary counts, the full control tree and ISINs, in one item.

- **URL**: https://apify.com/br_data_hub/lei-corporate-tree.md
- **Developed by:** [br_data_hub](https://apify.com/br_data_hub) (community)
- **Categories:** Lead generation, AI, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 entities

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LEI Lookup & Corporate Ownership Tree, from GLEIF data

> Independent tool. Not affiliated with, endorsed or sponsored by GLEIF (Global Legal Entity Identifier Foundation). It only reads GLEIF's open data.

Look up any legal entity by its **LEI** (Legal Entity Identifier) or by **company name**, and get one clean item with its official registry data, its **direct and ultimate parent**, how many **subsidiaries** it controls, the **full control tree** down to N levels and the **ISINs** mapped to it. All data comes from the official Global LEI Index published by GLEIF.

Built for KYC/AML onboarding, supplier and counterparty checks, group exposure analysis and enriching financial datasets with LEIs.

### Why this Actor

- **The whole group in one item.** Other LEI tools return the loose registry record; you then have to call parents and children yourself. Here every item already carries the parent chain up to the top of the group and a nested tree of subsidiaries (`controlTree`), with depth and size limits you choose.
- **Name search that finds the right company.** Names are ranked by similarity ignoring case, accents and legal forms (Inc, GmbH, S.A., AG...), with an optional country filter and a fuzzy fallback for typos. You get the `matchScore` and the next best candidates for free.
- **ISIN ↔ LEI** from GLEIF's official mapping, with the total count.
- **No API key, no browser, no proxy.** It calls GLEIF's public JSON API and respects its rate limit.

### Input

| Field | Description |
|---|---|
| `leis` | LEI codes (20 characters). Check digits (ISO 17442) are validated before any lookup. |
| `names` | Company names to search. Up to 200 LEIs and names per run. |
| `country` | Optional ISO two-letter country of the legal address (e.g. `BR`, `US`, `DE`), used for name search. |
| `matchesPerName` | Best-ranked entities returned per name (default 1). |
| `minMatchPercent` | Minimum name similarity, 0 to 100 (default 60). |
| `maxDepth` | Levels of subsidiaries in the tree (default 2, `0` turns the tree off). |
| `maxNodes` | Maximum entities per tree (default 30, up to 500). `treeTruncated` tells you when the limit was hit. |
| `treeFrom` | `entity` (its subsidiaries) or `ultimateParent` (the whole group). |
| `includeParentChain` | List every direct parent up to the top (default `true`). |
| `maxIsins` | ISINs listed per entity (default 20, `0` skips them). The total count is always returned. |

The default input (Apple Inc. by LEI and "Siemens" in Germany by name) needs at most about 80 GLEIF requests, about one and a half minutes at the rate limit.

### Output

One item per entity found:

```json
{
  "input": "Example Holding",
  "matchScore": 1.0,
  "alternatives": [
    {
      "matchScore": 0.8295,
      "lei": "5299EXTRAD0000000045",
      "legalName": "EXAMPLE HOLDINGS TRADING GMBH",
      "country": "DE",
      "jurisdiction": "DE",
      "entityStatus": "ACTIVE",
      "registrationStatus": "ISSUED"
    }
  ],
  "lei": "5299EXHOLD0000000010",
  "legalName": "EXAMPLE HOLDING SE",
  "entityStatus": "ACTIVE",
  "entityCategory": "GENERAL",
  "legalFormCode": "SGST",
  "jurisdiction": "DE",
  "country": "DE",
  "legalAddress": {
    "lines": [
      "Beispielstrasse 1"
    ],
    "city": "Berlin",
    "region": null,
    "postalCode": "10115",
    "country": "DE"
  },
  "registrationStatus": "ISSUED",
  "initialRegistrationDate": "2013-06-01",
  "nextRenewalDate": "2027-06-01",
  "gleifUrl": "https://search.gleif.org/#/record/5299EXHOLD0000000010",
  "directParent": null,
  "directParentException": {
    "category": "DIRECT_ACCOUNTING_CONSOLIDATION_PARENT",
    "reason": "NATURAL_PERSONS"
  },
  "ultimateParent": null,
  "isUltimateParent": true,
  "parentChain": [],
  "directChildrenCount": 2,
  "ultimateChildrenCount": 4,
  "treeRootLei": "5299EXHOLD0000000010",
  "controlTree": {
    "lei": "5299EXHOLD0000000010",
    "legalName": "EXAMPLE HOLDING SE",
    "country": "DE",
    "jurisdiction": "DE",
    "entityStatus": "ACTIVE",
    "registrationStatus": "ISSUED",
    "level": 0,
    "children": [
      {
        "lei": "5299EXSUBA0000000045",
        "legalName": "EXAMPLE SUB A GMBH",
        "country": "DE",
        "jurisdiction": "DE",
        "entityStatus": "ACTIVE",
        "registrationStatus": "ISSUED",
        "level": 1,
        "children": [
          {
            "lei": "5299EXSA1X0000000081",
            "legalName": "EXAMPLE A1 S.A.",
            "country": "BR",
            "jurisdiction": "BR",
            "entityStatus": "ACTIVE",
            "registrationStatus": "ISSUED",
            "level": 2,
            "children": []
          }
        ],
        "directChildrenCount": 2
      },
      {
        "lei": "5299EXSUBB0000000093",
        "legalName": "EXAMPLE SUB B LTD",
        "country": "GB",
        "jurisdiction": "GB",
        "entityStatus": "ACTIVE",
        "registrationStatus": "ISSUED",
        "level": 1,
        "children": [],
        "directChildrenCount": 0
      }
    ],
    "directChildrenCount": 2
  },
  "treeNodeCount": 5,
  "treeDepth": 2,
  "treeTruncated": false,
  "isinCount": 3,
  "isins": [
    "DE000EX00001",
    "DE000EX00019",
    "XS0000000019"
  ],
  "warnings": []
}
```

The example is real output of this Actor on the recorded test responses (`tests/fixtures`): the companies and LEIs are fictitious, the shape is GLEIF's. The tree is shortened here.

- Parent fields follow GLEIF's Level 2 data (accounting consolidation). When an entity does not report a parent, `directParentException` / `ultimateParentException` gives GLEIF's reason (e.g. `NATURAL_PERSONS`, `NON_CONSOLIDATING`, `NO_KNOWN_PERSON`).
- Invalid LEIs, unknown LEIs and names with no good match return an item with an `error` field and are **not charged**.
- If a secondary lookup fails (for example ISINs), the item is still returned and the problem is listed in `warnings`.
- **Personal data:** sole proprietors (`entityCategory` = `SOLE_PROPRIETOR`) are natural persons. Their name is masked and their street address and postal code are removed (`personalDataMasked: true`).

### How much does it cost?

Pay per event: **`entity`**, one per main entity returned. Tree nodes, parents, alternatives and ISINs come in the same item at no extra cost. Errors are free.

| Event | When | Suggested price |
|---|---|---|
| `entity` | Each entity returned (tree, parents, alternatives and ISINs included) | US$ 0.005 (US$ 5 per 1,000) |
| `apify-actor-start` | Once per run (Apify's standard start event, charged by the platform) | US$ 0.00005 |

No platform usage is billed on top.

- Compute: the run uses 128 MB. GLEIF allows about one request per second, so time is driven by the number of requests: about 5 to 10 per entity, plus one per tree node expanded. A default entity (tree of 30) costs about 0.0015 CU ≈ US$ 0.0003; the largest tree allowed (500 nodes) costs about 0.018 CU ≈ US$ 0.0035.
- After Apify's 20% commission, US$ 0.005 leaves US$ 0.004: more than 10× the compute of a typical entity and still positive in the worst case.
- Store references (October 2026, flat records without the ownership tree): about US$ 2.50 to 9.60 per 1,000 records.

**$0.005 per entity** (`entity` event, pay per event). Charged once per valid legal entity returned with its ownership data. Invalid and repeated LEIs are free.

- `apify-actor-start`: $0.00005 (Charged once when a run starts (Apify synthetic event).)

| You get | Free tier | Bronze tier (10% off) | Gold tier (30% off) |
|---|---|---|---|
| 100 entitys | $0.50 | $0.45 | $0.35 |
| 1,000 entitys | $5.00 | $4.50 | $3.50 |
| 10,000 entitys | $50.00 | $45.00 | $35.00 |

Discounts follow your Apify subscription tier: Bronze 10%, Silver 20%, Gold and above 30%. No subscription to this Actor and no charge for platform usage: you pay only for results.
The Apify Free plan includes $5 of monthly credit, enough for about **1,000 entitys** at the list price.
You can cap the cost of any run with **Maximum cost per run**; the Actor stops when it is reached.

### Data source

[GLEIF – Global Legal Entity Identifier Foundation](https://www.gleif.org), public API `https://api.gleif.org/api/v1` (LEI records, Level 2 relationship data, reporting exceptions and the ISIN-to-LEI mapping). GLEIF publishes LEI data free of charge under the **CC0 1.0** public domain dedication, which allows commercial reuse without attribution ([LEI Data Terms of Use](https://www.gleif.org/en/meta/lei-data-terms-of-use)). This Actor is independent and not affiliated with or endorsed by GLEIF. GLEIF limits requests per client; if it answers "too many requests", the Actor waits and retries, and gives a clear error (not charged) if it still cannot get an answer. Data freshness follows GLEIF (updated several times a day).

### More questions

#### Does the control tree show shareholders or ownership percentages?

No. The tree uses GLEIF's Level 2 data: who consolidates whom in the accounts (direct and ultimate accounting parent). It does not list shareholders, stakes or percentages, and natural persons never appear as parents. A subsidiary appears in the tree because it reported this entity as its direct parent to GLEIF.

#### Why does an entity have no parent?

Either it is the top of its group (`isUltimateParent: true`) or it did not report one. In that case `directParentException` / `ultimateParentException` gives GLEIF's reason, such as `NATURAL_PERSONS` (controlled by people), `NON_CONSOLIDATING` (the parent does not consolidate it) or `NO_KNOWN_PERSON`.

#### Are lapsed or closed LEIs returned?

Yes. The item is returned as GLEIF holds it: `registrationStatus` shows `LAPSED` or `RETIRED` and `nextRenewalDate` shows when renewal was due; `entityStatus` is `INACTIVE` for entities that ceased to exist, with `expirationDate`, `expirationReason` and `successorLei` when GLEIF has them. Use these fields to spot counterparties whose LEI needs renewal.

#### How does the name search choose the company?

It runs GLEIF's full-text search (filtered by `country` if you give one) and, when that finds nothing, GLEIF's fuzzy completions, which absorb typos. Candidates are then ranked by similarity with the legal name and other names, ignoring case, accents and legal forms (Inc, GmbH, S.A., AG...). Active entities with issued LEIs win ties. The best `matchesPerName` above `minMatchPercent` are returned and charged; up to five next best candidates come free in `alternatives`. Below the threshold you get a free error item with the best score.

#### What happens with groups that have thousands of subsidiaries?

The tree is built level by level until `maxDepth` or `maxNodes` (up to 500) is reached, and `treeTruncated` is `true` when a limit cut it. The totals are always there: `directChildrenCount` and `ultimateChildrenCount` count every subsidiary GLEIF knows, even those beyond the limit. Tree nodes are never charged; only the main entity is. Set `treeFrom` to `ultimateParent` to see the whole group from the top.

#### How fast is it, and how many companies per run?

GLEIF allows about one request per second, and the Actor respects that. An entity takes about 5 to 10 requests plus one per tree node expanded, so the default input (two companies, trees of 30) takes about a minute and a half. Up to 200 LEIs and names per run. If GLEIF answers "too many requests", the Actor waits and retries; a lookup that still fails returns a free error item.

#### Am I charged twice if the same company comes up twice?

No. LEIs written in different ways (spaces, lower case) are cleaned and checked once, and an entity found by both an LEI and a name search is returned and charged once per run. Invalid LEIs (wrong length or check digits) are rejected before any request, free.

#### How fresh is the data?

Every run reads GLEIF's live API, which GLEIF updates several times a day. Nothing is cached between runs.

### Use it via API

Run it from any language and get the results as JSON. Replace `<YOUR_API_TOKEN>` with your [Apify API token](https://console.apify.com/settings/integrations).

```bash
curl -X POST "https://api.apify.com/v2/acts/br_data_hub~lei-corporate-tree/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"leis": ["HWUPKR0MPOU8FGXBT394"], "names": ["Siemens"], "country": "DE"}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("br_data_hub/lei-corporate-tree").call(run_input={'leis': ['HWUPKR0MPOU8FGXBT394'], 'names': ['Siemens'], 'country': 'DE'})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

You can also schedule runs, send results to webhooks, or connect the Actor to Make, Zapier, n8n, Google Sheets and other [integrations](https://docs.apify.com/platform/integrations).

### Use it with AI agents (MCP)

This Actor is ready for AI agents: typed input and output schemas, pay-per-event pricing, limited permissions and short runs.

- **Apify MCP server:** add `https://mcp.apify.com/?tools=br_data_hub/lei-corporate-tree` to Claude, ChatGPT, Cursor, VS Code or any MCP client, and the agent can call this Actor as a tool.
- **Agent frameworks:** call it from LangChain, LlamaIndex, CrewAI or the OpenAI Agents SDK through the Apify integrations, or with the API call above.
- Results come as structured JSON with stable field names, documented in the **Output** tab.

### FAQ

#### Where does the data come from?

[GLEIF – Global Legal Entity Identifier Foundation](https://www.gleif.org), public API `https://api.gleif.org/api/v1` (LEI records, Level 2 relationship data, reporting exceptions and the ISIN-to-LEI mapping). GLEIF publishes LEI data free of charge under the **CC0 1.0** public domain dedication, which allows commercial reuse without attribution ([LEI Data Terms of Use](https://www.gleif.org/en/meta/lei-data-terms-of-use)). This Actor is independent and not affiliated with or endorsed by GLEIF. GLEIF limits requests per client; if it answers "too many requests", the Actor waits and retries, and gives a clear error (not charged) if it still cannot get an answer. Data freshness follows GLEIF (updated several times a day).

#### How much does it cost?

$0.005 per entity. Discounts follow your Apify subscription tier: Bronze 10%, Silver 20%, Gold and above 30%. See **How much does it cost?** above for examples.

#### Do I pay for errors or empty results?

No. Charged once per valid legal entity returned with its ownership data. Invalid and repeated LEIs are free.

#### Can I run it on a schedule or connect it to other tools?

Yes. Use Apify schedules to run it daily or weekly, webhooks to get notified, and integrations such as Make, Zapier, n8n and Google Sheets. Everything also works through the API.

#### Can AI agents use it?

Yes. It works as a tool in the Apify MCP server and in agent frameworks, and AI agents can pay per event. See **Use it with AI agents (MCP)**.

#### Is it legal to use this data?

The Actor reads only public sources. You are responsible for how you use the data and for complying with the source's terms and with privacy laws such as GDPR.

#### I found a bug or need a feature. What should I do?

Open an issue in the **Issues** tab. We answer within 14 days, usually much sooner.

### More Actors from BR Data Hub

| Actor | What it does |
|---|---|
| [EU VAT Number Bulk Validator (from VIES data)](https://apify.com/br_data_hub/eu-vat-validator) | Bulk-check EU and Northern Ireland (XI) VAT numbers using the European Commission's public VIES service: valid |
| [Sanctions Screening: OFAC, UN, EU, UK](https://apify.com/br_data_hub/global-sanctions-screening) | Screen people and companies using data from the official OFAC SDN and Consolidated, UN Security Council, EU an |
| [US Company Financials from SEC XBRL Data (normalized)](https://apify.com/br_data_hub/sec-company-financials) | Standardized financial statements of US-listed companies, built from public SEC XBRL data: revenue, profits, E |
| [Entity Resolver & ID Crosswalk (from Wikidata data)](https://apify.com/br_data_hub/wikidata-entity-resolver) | Resolve company, brand, organization and place names to the right Wikidata entity with an explained confidence |
| [EU Public Tenders Search, from TED data](https://apify.com/br_data_hub/eu-ted-tenders) | Search European public tenders using open data from TED (Tenders Electronic Daily), the EU procurement journal |

See all our Actors at [apify.com/br_data_hub](https://apify.com/br_data_hub).

### Usar em português

Informe códigos LEI ou nomes de empresas (com país opcional) e receba, num único item, os dados oficiais da entidade na GLEIF (nome legal, endereço, situação, datas de registro e renovação, jurisdição, forma jurídica), a controladora direta e a final, o número de controladas, a árvore de controle até N níveis e os ISINs ligados ao LEI. A busca por nome ordena por semelhança e aceita filtro por país. Cobrança por entidade devolvida (evento `entity`); a árvore vem junto sem custo extra e erros não são cobrados. Empresários individuais têm nome e endereço mascarados.

**Quanto custa:** $0.005 por resultado (`entity`); 1.000 resultados saem por $5.00. Desconto pelo nível da assinatura Apify: Bronze 10%, Silver 20%, Gold ou acima 30%. Erros e consultas sem resultado não são cobrados. Use também pela API ou por agentes de IA no servidor MCP da Apify (`https://mcp.apify.com/?tools=br_data_hub/lei-corporate-tree`).

# Actor input Schema

## `leis` (type: `array`):

Enter Legal Entity Identifiers (20 characters), one per line, e.g. HWUPKR0MPOU8FGXBT394. Check digits are validated before any lookup. Up to 200 LEIs and names per run.

## `names` (type: `array`):

Enter company names to search in GLEIF, one per line, e.g. Siemens. Results are ranked by name similarity; case, accents and legal forms such as Inc, GmbH or S.A. are ignored.

## `country` (type: `string`):

Type an ISO two-letter country code of the legal address, e.g. BR, US or DE. Applies to the name search only.

## `matchesPerName` (type: `integer`):

Set how many best-ranked entities to return for each name, e.g. 1. Each is a charged result; the next candidates come free in the alternatives field.

## `minMatchPercent` (type: `integer`):

Set the name similarity (0 to 100) a candidate needs, e.g. 60 (100 = same name after normalization). Below it you get a free error item instead.

## `maxDepth` (type: `integer`):

Set how many levels of subsidiaries to expand in the control tree, e.g. 2. Use 0 to turn the tree off.

## `maxNodes` (type: `integer`):

Set the maximum entities in each control tree, e.g. 30. Large groups have thousands of subsidiaries; when the limit is hit, treeTruncated is true. Tree nodes are never charged.

## `treeFrom` (type: `string`):

Pick 'The entity' to start the tree at the entity itself (its subsidiaries) or 'Its ultimate parent' to show the whole group.

## `includeParentChain` (type: `boolean`):

Keep on to list every direct parent from the entity up to the top of the group (one extra request per level).

## `maxIsins` (type: `integer`):

Set how many ISIN codes mapped to the LEI by GLEIF to return, e.g. 20. The total count is always returned; 0 skips ISINs.

## Actor input object example

```json
{
  "leis": [
    "HWUPKR0MPOU8FGXBT394"
  ],
  "names": [
    "Siemens"
  ],
  "country": "DE",
  "matchesPerName": 1,
  "minMatchPercent": 60,
  "maxDepth": 2,
  "maxNodes": 30,
  "treeFrom": "entity",
  "includeParentChain": true,
  "maxIsins": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with all results

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "leis": [
        "HWUPKR0MPOU8FGXBT394"
    ],
    "names": [
        "Siemens"
    ],
    "country": "DE"
};

// Run the Actor and wait for it to finish
const run = await client.actor("br_data_hub/lei-corporate-tree").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "leis": ["HWUPKR0MPOU8FGXBT394"],
    "names": ["Siemens"],
    "country": "DE",
}

# Run the Actor and wait for it to finish
run = client.actor("br_data_hub/lei-corporate-tree").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "leis": [
    "HWUPKR0MPOU8FGXBT394"
  ],
  "names": [
    "Siemens"
  ],
  "country": "DE"
}' |
apify call br_data_hub/lei-corporate-tree --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,br_data_hub/lei-corporate-tree"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/BP5iozUd5E3c1DMyQ/builds/6iNRj02UNbHsbrs2F/openapi.json
