Who controls this counterparty? The GLEIF parent hierarchy

One call returns the declared consolidation chain above a LEI — direct parent, ultimate parent, subsidiaries — and why that is not beneficial ownership.

By Matthias Begot · · Updated

An agent screened its counterparty and got a clean result. That tells it about the counterparty. It says nothing about the group that consolidates it — and a spotless subsidiary of a designated parent is exactly the case an endpoint-by-endpoint review walks past. GET /company/ownership answers the missing question from a LEI: the direct parent, the ultimate parent, the dated chain between them, and the direct subsidiaries — served offline from the GLEIF Level 2 relationship records, published under CC0.

The first thing worth writing down is what the response is not, because the response itself says so. This article walks both: the chain, and its boundary, with captures taken from production on 11 August 2026 against the GLEIF snapshot dated 2026-08-10.

The distinction the response states about itself

GLEIF Level 2 publishes the accounting consolidation parent — the entity that consolidates this one in its financial statements. That is a different object from the ultimate beneficial owner under AML rules, and every 200 carries a fixed data.limits sentence saying so:

Relationships are self-declared by the entities to GLEIF and describe accounting consolidation (the parent that consolidates the entity in its financial statements). This is NOT beneficial ownership under AML/KYC rules, and Level 2 publishes no ownership percentage. The absence of a declared parent is not evidence of an absence of control.

Three consequences an integration has to respect:

  • No percentages. Level 2 publishes none, so none are served. A UBO determination under Regulation (EU) 2024/1624 turns on a 25%-or-more ownership interest from 10 July 2027 — a number this dataset does not contain and cannot be made to yield.
  • No public shortcut exists. Since the Court of Justice struck down unrestricted public access to national beneficial-ownership registers in WM and Sovim SA v Luxembourg Business Registers on 22 November 2022 (CJEU press release 188/22), access runs through a legitimate-interest regime. No pay-per-call API — this one included — is going to hand an agent a UBO.
  • Absence is not evidence. “No declared parent” means the register holds no declaration. It does not mean nobody is above.

Selling a consolidation parent as a beneficial owner would be selling one piece of data as another. The endpoint states the distinction instead of letting an integration assume it away.

One call, and the group above

GET /company/ownership?lei=F0HUI1NY1AZMJMD8LP67&depth=5 — a French bank whose control chain leaves France in one hop:

{
  "data": {
    "query": { "lei": "F0HUI1NY1AZMJMD8LP67", "direction": "up", "depth": 5 },
    "subject": { "legal_name": "HSBC CONTINENTAL EUROPE", "legal_country": "FR",
                 "entity_status": "ACTIVE", "registration_status": "ISSUED" },
    "direct_parent": {
      "status": "declared",
      "link": { "lei": "MP6I5ZYZBEU3UXPYFY54",
                "entity": { "legal_name": "HSBC BANK PLC", "legal_country": "GB" },
                "relationship_status": "ACTIVE",
                "period": { "start": "2012-06-06", "end": null } },
      "exception": null
    },
    "ultimate_parent": {
      "status": "declared",
      "link": { "lei": "MLU0ZO3ML4LN2LL2TL39",
                "entity": { "legal_name": "HSBC HOLDINGS PLC", "legal_country": "GB" },
                "relationship_status": "ACTIVE",
                "period": { "start": "2012-06-06", "end": null } },
      "exception": null
    },
    "chain": [
      { "entity": { "legal_name": "HSBC BANK PLC", "legal_country": "GB" }, "period": { "start": "2012-06-06" } },
      { "entity": { "legal_name": "HSBC HOLDINGS PLC", "legal_country": "GB" }, "period": { "start": "2024-06-30" } }
    ],
    "chain_truncated": false,
    "cycle_detected": false,
    "limits": "…"
  },
  "provenance": { "source": "gleif", "freshness": { "kind": "snapshot", "as_of": "2026-08-10T00:00:00Z" } }
}

The counterparty is French; the entity that consolidates it is not, and the jurisdiction that matters for a group-level check moved with it. That is the whole value of the call: an agent holding an IBAN can go /iban/resolve/company/lei/company/ownership and end on a group head it can then screen with GET /screen/entity.

direction controls the walk — up (default), down, or both — and depth bounds the upward walk between 1 and 5. A depth outside that range is a 400, never a silent clamp: an agent that asked for 7 has to know it was not served at 7.

99% of registrants report a parent. About 4% name one.

GLEIF reports that over 3.13 million registrants — 99% of the active LEI population — reported direct and ultimate parent information in Q1 2026 (GLEIF, The LEI in Numbers, 28 April 2026). Read quickly, that sounds like near-total ownership coverage. It is not, and the gap is the single most useful thing to understand before wiring this endpoint.

In the ingested 2026-08-10 snapshot — 3,398,502 LEI records — 139,852 entities declare at least one consolidation relationship, and 3,157,691 carry a reporting exception instead. “Reported parent information” mostly means declared a reason for having no parent to report. Only 53,904 distinct entities are ever named as somebody’s parent.

Those reasons are the payload in the overwhelming majority of calls, so they are served raw, with the GLEIF codes as published. Counts below are direct-parent exceptions in that snapshot; the official definitions are GLEIF’s, from the Reporting Exceptions 2.1 format.

reasons codeWhat the entity declaredRecords
NATURAL_PERSONSControlled by natural person(s), no intermediate legal entity1,162,019
NON_CONSOLIDATINGControlled by legal entities not subject to consolidation1,095,374
NO_KNOWN_PERSONNo known person controls the entity — diverse shareholders664,473
NO_LEIThe parent exists but has no LEI123,113
NON_PUBLICDisclosure barred by law, contract, detriment or missing consent108,741
five codes GLEIF deprecated on 1 March 2022Still published on old records1,996

Two readings to resist. First, the codes are self-declared and not normalized across filers: in this same snapshot BNP Paribas and Société Générale both sit at the top of their group and both declare NO_KNOWN_PERSON, while HSBC Holdings plc and Caisse des dépôts et consignations declare NON_CONSOLIDATING for a materially similar situation. Branch on status; treat the code as evidence to record, not as a taxonomy to compute on. Second, NON_PUBLIC is an answer, not a failure — the entity is telling you it will not say, which is itself a fact worth keeping.

The deprecated codes are passed through rather than folded into NON_PUBLIC: 4,008 rows across 2,171 entities still carry them, and rewriting what a filer declared would be inventing data.

Three statuses, and an empty chain that is not an absence

direct_parent and ultimate_parent share one shape and exactly three states:

statusMeaningPopulated
declaredA relationship is publishedlink
reporting_exceptionThe entity published a reason for having no parent to reportexception
not_declaredNeither a relationship nor a published exceptionneither

link and exception are never both populated, and the three are not interchangeable. Here is the trap, captured live — GET /company/ownership?lei=21380023ZW5TAIN7YO53:

{
  "subject": { "legal_name": "HENSOLDT FRANCE SAS", "legal_country": "FR", "entity_status": "ACTIVE" },
  "direct_parent": {
    "status": "reporting_exception", "link": null,
    "exception": { "category": "DIRECT_ACCOUNTING_CONSOLIDATION_PARENT", "reasons": ["NO_LEI"] }
  },
  "ultimate_parent": {
    "status": "declared",
    "link": { "lei": "894500686FYLLZD3M624",
              "entity": { "legal_name": "HENSOLDT AG", "legal_country": "DE" },
              "relationship_status": "ACTIVE", "period": { "start": "2020-09-21", "end": null } },
    "exception": null
  },
  "chain": [],
  "chain_truncated": false
}

chain is empty and the ultimate parent is a German group. The walk cannot start, because the first link up is missing — the direct parent has no LEI, so no relationship record exists to follow — but the ultimate parent is served anyway, since it is declared in its own right rather than derived from the walk. An agent that reads chain.length === 0 and concludes “no group above this entity” has just mis-cleared a subsidiary of a European defence group.

Read ultimate_parent.status first. chain is the path, not the verdict.

The third state is real too, and it shows up next to the others. SGS FRANCE SAS (2138001NYOEQGV4ZNG76) declares NO_LEI on its direct parent and is not_declared at the ultimate level — nothing published, not even a reason. The subject itself comes back entity_status: "INACTIVE", registration_status: "RETIRED", served as-is: a diligence signal for the agent’s own policy, not a verdict the service passes.

Downward: capped, counted, and moving

GET /company/ownership?lei=R0MUWSFPU8MPRO8K5P83&direction=down returns the entities declaring BNP Paribas as their direct parent — 141 of them in the 2026-08-10 snapshot, of which 100 are served:

{
  "subject": { "legal_name": "BNP PARIBAS", "legal_country": "FR" },
  "direct_parent": { "status": "reporting_exception", "link": null,
                     "exception": { "category": "DIRECT_ACCOUNTING_CONSOLIDATION_PARENT",
                                    "reasons": ["NO_KNOWN_PERSON"] } },
  "chain": null,
  "direct_children": [
    { "lei": "2138002ONAA2E7MTAD20", "entity": { "legal_name": "BNP PARIBAS SYNERGY LIMITED", "legal_country": "GB" },
      "relationship_status": "ACTIVE", "period": { "start": "2014-05-15", "end": null } },
    { "lei": "21380036SM8RMK9HM241", "entity": { "legal_name": "CARDIF COLOMBIA SEGUROS GENERALES S A", "legal_country": "CO" },
      "relationship_status": "ACTIVE", "period": { "start": "2017-07-11", "end": null } },
    { "lei": "2138003E7UBOEXP61F19", "entity": { "legal_name": "法銀巴黎證券股份有限公司", "legal_country": "TW" },
      "relationship_status": "ACTIVE", "period": { "start": "2014-04-22", "end": null } }
  ],
  "children_truncated": true,
  "total_children": 141
}

Three properties of that block are contract, not implementation detail.

  • The cap is 100 and the total is exact. children_truncated: true beside total_children: 141 means the agent always knows whether the list hid something. A truncated list without its count is a silent lie.
  • chain: null is not chain: []. null means “you did not ask for this block”; [] means “you asked, and the reference declares nothing”. The service never collapses one into the other, in either direction.
  • Only direct subsidiaries. There is no multi-level downward org chart, and depth does not apply going down.

The same call documented on the endpoint page returned 137 against the 2026-07-28 image. Four subsidiaries in thirteen days — which is why provenance.freshness.as_of belongs in whatever the agent stores. Six months from now, “on what basis did the agent clear this counterparty” is answerable only if the date was kept with the answer.

Served as published, including the awkward records

Relationship statuses are passed through as GLEIF publishes them, including the literal string NULL that sits on a handful of old records — six, in this snapshot. GET /company/ownership?lei=213800TQ8Q2668XD1U88 is one:

{
  "subject": { "legal_name": "BIG BEAR CONFECTIONERY LIMITED", "legal_country": "GB",
               "entity_status": "INACTIVE", "registration_status": "RETIRED" },
  "direct_parent": { "status": "declared",
    "link": { "entity": { "legal_name": "RAISIO UK LIMITED", "legal_country": "GB" },
              "relationship_status": "NULL",
              "period": { "start": "2018-01-01", "end": "2018-12-31" } } },
  "ultimate_parent": { "status": "declared",
    "link": { "entity": { "legal_name": "Raisio Oyj", "legal_country": "FI" },
              "relationship_status": "ACTIVE",
              "period": { "start": "2018-01-01", "end": "2018-12-31" } } }
}

A closed period.end, one link marked NULL and one marked ACTIVE on the same record. Normalizing that into a tidy "ACTIVE" would make the response prettier and wrong. Where several relationships do compete, the selection is deterministic and stated: a parent in force beats a historical one — an ACTIVE link wins over an INACTIVE one, then the most recent period, then the LEI. The order never depends on what the storage engine happens to return, because serving a stale link would name a wrong parent.

Two more guards behave the same way. A declared parent whose own Level 1 record is absent is served with its LEI and entity: null — the link is published, the identity record is not, and neither is hidden nor invented. And the upward walk keeps the set of visited LEIs: an already-seen LEI stops it and raises cycle_detected: true. Real consolidation data has no cycles, but nothing in the format forbids one, and an infinite loop on a valid input would be a 5xx or worse.

Billing and failure modes

Everything the service can answer is a billed 200, including every form of “the register declares nothing here”. Everything it cannot answer leaves the 200 range and is not billed.

CaseResult
Chain found, up, down or both200, billed
reporting_exception — a reason instead of a parent200, billed
not_declared, empty chain, empty direct_children200, billed
lei absent400 MISSING_PARAMETER, not billed
depth outside 1..5, unknown direction, malformed lei400 INVALID_INPUT, not billed
Well-formed LEI failing its ISO 17442 check digits400 INVALID_CHECKSUM, not billed
Well-formed LEI unknown to the reference404 NOT_FOUND, not billed
GLEIF dataset not ingested503 DATA_UNAVAILABLE, not settled

The two 400s that look alike are deliberately distinct, because they demand opposite reactions — fix the input, versus conclude the entity is not in the register:

GET /company/ownership?lei=R0MUWSFPU8MPRO8K5P84
→ 400 { "code": "INVALID_CHECKSUM", "error": "lei failed its ISO 17442 check digits: likely a typo" }

GET /company/ownership?lei=R0MUWSFPU8MPRO8K5P83&depth=7
→ 400 { "code": "INVALID_INPUT", "error": "depth must be between 1 and 5" }

A missed refresh keeps serving the last good snapshot under its honest as_of — staleness is declared in provenance.freshness, never turned into a 5xx.

Wiring it up

  1. Get a LEI first. This route takes nothing else. GET /company/lei reaches one from a BIC, an ISIN, a SIREN or an exact name plus country.
  2. Branch on ultimate_parent.status, never on chain.length. The HENSOLDT capture is the reason: an empty walk can sit under a named group.
  3. Treat reporting_exception as data. Store the code. NATURAL_PERSONS and NON_PUBLIC are different facts about your counterparty, and neither is an error.
  4. Screen the parent you found. Naming a group head is not clearing it; GET /screen/entity is the check this one sets up.
  5. Keep as_of with the answer. The subsidiary count moved by four in under two weeks.
  6. Discover, then pay. The 402 → pay → replay cycle is walked with runnable snippets in the Quickstart, and the machine discovery surfaces are described in For agents.

Every amount and every accepted settlement rail lives in the gateway’s /catalog, which is the single source of truth — no price appears in this article. If you would rather not orchestrate steps 1, 2 and 4 yourself, GET /preflight/supplier runs identity, insolvency, VAT, reachability, the control chain and the screening of the ultimate parent in one settlement and returns a single verdict; and GET /company/report bundles the French counterparty picture by SIREN, ultimate parent included.

What none of them will do is name a beneficial owner. That answer is not in this dataset, it is not in any public one since 2022, and an endpoint that claimed otherwise would be worth less than one that says so. The full parameter and field contract is on the GET /company/ownership documentation.