| name | beneficial-ownership-data |
| version | 1.17.0 |
| description | Expert reference for beneficial ownership data, policy, and BODS. Trigger on: BODS JSON/schema/tools (bodsdata, CoVE-BODS, RDF/SPARQL, open issues), BO registries, FATF R24/R25, FATF mutual evaluations (MERs, FSRBs: APG/CFATF/MONEYVAL/ESAAMLG/MENAFATF/GIABA/EAG/GAFILAT), EU AML/AMLD6/AMLR/BORIS, country BO data (UK, Norway, France, Indonesia, Denmark, Canada/Ontario, Sri Lanka, BVI, Philippines, Ghana, Sweden), GLEIF, corporate data (OpenCorporates, Kyckr, Kausate, Sayari, ICIJ), FtM/OpenSanctions, Neo4j, BODS case studies (Latvia, Armenia, Nigeria), BO in procurement (OCDS, ChileCompra, Slovakia, PhilGEPS), BO in energy/extractives (EITI, GEM), BO in fisheries (GFW, FiTI), BO forms (Ghana, Namibia, PSC01), ICIJ/Panama Papers, BO reports (World Bank, TI, TI-UK), GODIN, UBO APIs (Kyckr, Kausate, KvK, Signicat, Companies House), BO verification (FATF, OECD toolkit, TJN), BOVS, or 2026 developments (BVI, Sri Lanka, Sweden, Ontario, Philippines, St Helena). If the question is about who owns what, use this skill. |
Beneficial Ownership Data — Expert Reference
This skill covers the full beneficial ownership data landscape: the BODS technical standard, OpenOwnership's ecosystem of tools, the regulatory policy context (FATF, EU AML), country-specific register designs, international advocacy, mapping corporate data sources to BODS, interoperability with other data models, beneficial ownership in procurement, and beneficial ownership in extractives.
Important context: This skill is used by Stephen Abbott Pugh — the original product owner of BODS at Open Ownership, now running the consultancy Understand Beneficial Ownership (beneficialownership.co.uk). His writing is at stephenabbottpugh.medium.com and beneficialownership.co.uk/news-articles-and-blog-posts. When helping Stephen, you can assume deep domain expertise on his part — be direct and specific rather than over-explaining fundamentals.
Always fetch live documentation when you need precise schema details; the standard is versioned and evolving.
Quick reference: Key URLs
BODS Standard & Tools
Stephen's BODS Conversion Repositories
GLEIF → BODS 0.4
Corporate Ownership Data Sources
Private Sector & Register APIs: UBO/PSC Data
Neo4j Graph Database: BO Ownership Analysis
BODS Interoperability: Other Data Models
BODS RDF: Linked Data & SPARQL
Beneficial Ownership in Procurement
Beneficial Ownership in Extractives (EITI)
Public Beneficial Ownership Registers
Policy & Regulation
FATF Mutual Evaluations & Country Reports
International Endorsements & Resources
Country-Specific Registers
EU BORIS: BO Registers Interconnection System
Stephen's Writing & Consultancy
BODS Case Studies & Implementations
Full case studies index: https://www.beneficialownership.co.uk/case-studies
ICIJ Investigations & Offshore Leaks
Key Beneficial Ownership Research Reports
GODIN: Global Open Data Integration Network
BO Declaration & Data Collection Forms
Beneficial Ownership Data Verification
BODS Development: GitHub Issues & Feature Tracker
Sectoral Use Cases: Energy & Extractives (Global Energy Monitor)
Sectoral Use Cases: Fisheries
For detailed reference material, read:
references/bods-standard.md — BODS 0.4 schema in depth
references/tools-ecosystem.md — OpenOwnership tools
references/regulatory-context.md — FATF, EU AML, policy context
references/international-registers.md — country-specific BO register APIs
The BODS Data Model
BODS represents beneficial ownership as a collection of Statements. The current version is 0.4.
Three statement types
1. Person Statements
Describe a natural person who holds or may hold a beneficial ownership interest.
Key fields: statementId, statementType: "personStatement", names[], identifiers[], nationalities[], birthDate, placeOfBirth, addresses[], pepStatus[], hasPepStatus.
2. Entity Statements
Describe a legal entity (company, trust, foundation, etc.) in the ownership chain.
Key fields: statementId, statementType: "entityStatement", entityType, names[], identifiers[], incorporatedInJurisdiction, addresses[], foundingDate, dissolutionDate, isComponent.
3. Ownership-or-Control Statements
Link a person or entity (the interested party) to an entity (the subject), describing the nature of their interest.
Key fields: statementId, statementType: "ownershipOrControlStatement", subject (entity statementId), interestedParty (person or entity statementId), interests[] (type, share, directOrIndirect), isComponent, componentStatementIDs[].
Key structural concepts
statementId: UUID-based unique identifier for each statement
isComponent: boolean; marks whether a statement is part of an indirect ownership chain (v0.4 addition)
componentStatementIDs: array of statementIds making up an indirect chain
publicationDetails: metadata on publisher, date, bodsVersion
- Temporal versioning: multiple statements can describe the same entity over time; use
replacesStatements[] to link them
A BODS dataset is a JSON array of statement objects. There is no wrapping container object — just a flat array.
Using BODS for Corporate Ownership Structures (without BO declarations)
BODS is designed for beneficial ownership but is equally capable of representing corporate ownership and control structures where the ultimate beneficial owners are unknown, undisclosed, or not the focus. This is a key use case for mapping commercial corporate data sources to BODS.
Why map corporate ownership data to BODS without BO declarations
Many real-world datasets — company registries, commercial data providers, financial data feeds — record legal entity ownership chains (parent/subsidiary relationships, shareholdings, directorship) without capturing natural-person beneficial owners. BODS accommodates this in several ways.
Entity-to-entity ownership: An ownership-or-control statement can link two entity statements, not just a person to an entity. This is the standard pattern for parent/subsidiary chains, joint ventures, and corporate group structures.
Unknown or anonymous interested parties: The interestedParty field supports unspecified as a value to indicate the interested party is not known. Use unknownPersons or anonymousEntity as the entity type when the ultimate owner is deliberately obscured or simply not recorded in the source data.
Partial chains: A dataset might record that Company A owns 60% of Company B, without knowing who owns Company A. This is perfectly valid BODS — just publish what is known. The isComponent flag and componentStatementIDs can be used to mark that a chain is incomplete.
entityType values for corporate structures: Beyond registeredEntity, BODS supports arrangement (for trusts, partnerships), anonymousEntity, unknownEntity, and stateBody. For offshore vehicles and special-purpose entities from sources like ICIJ Offshore Leaks, arrangement and anonymousEntity are most appropriate.
Mapping heuristics for source data without BO
When mapping a dataset that records corporate relationships but not BO:
- Map each company/legal entity to a BODS entity statement with the appropriate
entityType
- Map each ownership/control link to a BODS ownership-or-control statement with
entityType-based interestedParty
- For natural persons appearing in officer/director roles (not BO roles), create a person statement and an ownership-or-control statement with
interests[].type = "controlViaDirectorship" or "otherInfluenceOrControl"
- Use heuristics to distinguish natural persons from corporate entities when source data is ambiguous (e.g. ICIJ officer names that could be either)
- Record
interests[].share.exact where share percentages are available; otherwise leave omitted or use minimum/maximum fields
Stephen's BODS Conversion Repositories
These are Stephen's Python repositories for transforming third-party corporate data sources into BODS 0.4. All are pure Python, structured as src/bods_<source>/ packages with tests.
bods-icij-offshoreleaks
Source: ICIJ Offshore Leaks database — covering Panama Papers (2016), Pandora Papers (2021), Bahamas Leaks (2016), Paradise Papers (2017), Offshore Leaks (2013). 810,000+ offshore entities.
Mapping approach:
- ICIJ
Entity nodes → BODS entity statements (registeredEntity or arrangement for offshore vehicles)
- ICIJ
Officer nodes → person statements or entity statements (heuristics classify names as natural person vs. corporate)
- ICIJ
Intermediary nodes → entity statements (registeredEntity, service provider firms)
- ICIJ relationship types (
officer_of, intermediary_of, etc.) → BODS ownership-or-control statements with appropriate interests[].type
- Neo4J export also available for graph database workflows
Repo: https://github.com/StephenAbbott/bods-icij-offshoreleaks
bods-opencorporates
Source: OpenCorporates relationship data — the world's largest open company database, 200M+ companies.
OpenCorporates tracks four relationship types: control_statement, subsidiary, branch, and share_parcel. The Relationships Supplement contains 30M+ relationships extracted from primary datasets (SEC, UK Companies House, etc.).
Repo: https://github.com/StephenAbbott/bods-opencorporates
bods-brightquery
Source: BrightQuery corporate data via opendata.org — 324M organisations, 512M locations, 1.2B contacts across 222 countries. Government-sourced data including corporate family structures, legal status, and identity crosswalks (LEI, CIK, ISIN, NPI, etc.).
Repo: https://github.com/StephenAbbott/bods-brightquery
bods-kyckr
Source: Kyckr relationship data — a company intelligence platform providing corporate registry data and ownership relationships.
Repo: https://github.com/StephenAbbott/bods-kyckr
bods-ftm
Conversion: BODS 0.4 ↔ FollowTheMoney (FtM) — bidirectional.
Repo: https://github.com/StephenAbbott/bods-ftm
Note: this is distinct from the archived opensanctions/bods-ftm (which only converted OpenOwnership data dumps to FtM and is no longer maintained). Stephen's bods-ftm is a current, bidirectional converter designed for general BODS 0.4 data.
BODS → FtM mappings:
entityStatement → FtM Company
personStatement → FtM Person
ownershipOrControlStatement → FtM Ownership, Directorship, or UnknownLink (depending on interest type)
FtM → BODS mappings: reverse conversion using deterministic UUID5 hashing for consistent identifier generation.
Technical approach: two-pass processing (entities/persons first, then relationships); indirect ownership chains consolidated rather than split; converts between org-id.guide scheme codes (e.g., GB-COH) and FtM named properties (e.g., registrationNumber).
CLI: cli.py | Input: BODS or FtM JSON/JSONL | Output: converted format with full ownership relationship chains preserved.
bods-aml-ai
Conversion: BODS 0.4 → Google Anti-Money Laundering AI input format.
Repo: https://github.com/StephenAbbott/bods-aml-ai
Google's AML AI data model has no native concept of party-to-party ownership relationships, so the tool encodes beneficial ownership creatively through available AML AI constructs:
Output (three NDJSON files):
party.ndjson — persons and entities as COMPANY or CONSUMER types
party_supplementary_data.ndjson — numeric ownership attributes (e.g., bo_ownership_pct_{subject_id}, bo_is_beneficial_owner, interest types)
account_party_link.ndjson — synthetic "ownership accounts" linking subjects (PRIMARY_HOLDER) to owners (SUPPLEMENTARY_HOLDER)
CLI: cli.py | Input: BODS v0.4 JSON/JSONL | Output: NDJSON files for AML AI ingestion.
bods-neo4j
Conversion: BODS 0.4 ↔ Neo4j graph database — bidirectional, with built-in graph analysis.
Repo: https://github.com/StephenAbbott/bods-neo4j
Note: this is Stephen's BODS-native converter. For the broader Neo4j + UK Companies House PSC demo (without BODS), see erikbijl/neo4j-company-house-demo in the Neo4j section of Developer workflows.
Three primary workflows:
- BODS → Neo4j: import BODS ownership datasets into graph form via CSV export or direct driver loading; produces Neo4j-importable CSV files and Cypher scripts
- Neo4j → BODS: export graph data back to standardised BODS JSONL, preserving all metadata (round-trip fidelity)
- Graph analysis: built-in queries for UBO detection, corporate group mapping, and circular ownership identification
CLI: cli.py | Input: BODS v0.4 JSON/JSONL or Neo4j instance | Output: Neo4j CSVs/Cypher or BODS JSONL.
bods-xml
Conversion: BODS 0.4 JSON → XML, in two output modes.
Repo: https://github.com/StephenAbbott/bods-xml
Two modes:
- Canonical (
canonical.py): a faithful XML serialisation of BODS 0.4 that preserves every field and mirrors the JSON structure, under the standard's namespace
- MRAS preBODS (
profiles/mras.py): transforms the flat BODS statement array into Canada's Multijurisdictional Registry Access Service (MRAS) hierarchical XML format
Architecture: extensible profile system — additional output profiles (BORIS, XBRL, etc.) can be added as modules alongside the existing two.
CLI: cli.py | Input: BODS 0.4 JSON or JSONL | Output: XML | Tests: 31
bods-stream
Type: Live streaming web application — UK beneficial ownership changes in real time as BODS v0.4.
Repo: https://github.com/StephenAbbott/bods-stream
Live demo: https://bods-stream.onrender.com/
Consumes the Companies House PSC Streaming API and converts every live PSC (Person with Significant Control) filing event into BODS v0.4 statements the moment it's filed — displayed as a BOVS diagram with the raw Companies House event and the mapped BODS statements side by side.
This is notable because almost no beneficial ownership registers offer a streaming API. The UK PSC stream is the standout public exception, and BODS is purpose-built to represent change (recordStatus new/updated/closed, replacesStatements, append-only). bods-stream makes that change model visible live.
What you see per event:
- BOVS diagram: interested party → subject company, interest type on the edge, jurisdiction/nationality flags, identity-verification tick, tinted by lifecycle
- Lifecycle badge:
NEW / UPDATED / CEASED (driven by BODS recordStatus)
- Risk signals (structural, no external calls): FATF black/grey list, non-EU jurisdiction, trust/arrangement, nominee, super-secure (opaque), sanctioned flag
- Prolific PSC signal: flags when one person appears as PSC of multiple companies in the session
- Live insight bar: individual vs corporate split, cessation rate, identity-verification rate, prolific PSC of the day
- Top-20 PSC nationalities (live flag tally)
- Pause/play with live event counter
Architecture: FastAPI backend (SSE relay — one long-lived CH stream connection, fan-out to many browsers) + React/Vite frontend. Single-process, in-memory state (lifecycle tracking, prolific tracker); nothing persisted to disk.
Lifecycle handling: The CH stream has no new/updated/closed concept. bods-stream maintains an in-memory map keyed on resource_uri (stable PSC id) to emit correct recordStatus values and replacesStatements references, including reconstructing a closed record from last-seen state when a deletion event arrives.
Privacy: Address and date of birth stripped at ingress — never broadcast or shown in UI. Date of birth used only briefly in-process for the prolific disambiguator.
Key dependency: bods-mapper — a separate shared repo containing the core Companies House → BODS v0.4 mapping logic, used by both bods-stream and OpenCheck to prevent the two apps drifting.
Replay mode: Set BODS_STREAM_REPLAY_FILE to a captured .jsonl to feed pre-recorded events through the live pipeline (useful outside UK office hours when the live feed is quiet).
Deployment: Docker image builds frontend and serves it with the API (same origin). Deployed on Render via render.yaml. Must run as one instance/one worker (in-memory state).
bods-mapper
Type: Shared Python library — canonical UK Companies House PSC → BODS v0.4 mapping core.
Repo: https://github.com/StephenAbbott/bods-mapper
Extracted from OpenCheck so that both opencheck and bods-stream use one canonical mapper and cannot drift apart. Takes a single Companies House PSC streaming event (the data block is identical to the REST PSC endpoint response) and emits a BODS v0.4 bundle containing:
- the subject company entity statement
- the interested party — a
knownPerson (individual PSC), entity statement (corporate/legal-person PSC), or anonymousPerson (super-secure PSC)
- an ownership-or-control relationship statement
Key features:
- All 86 official
natures_of_control codes mapped to valid BODS interestType, each with the official Companies House short descriptor in interest.details
- Cessation lifecycle: a ceased PSC produces a relationship with
recordStatus: "closed" — stable recordId, distinct statementId, interest.endDate, and replacesStatements pointing to the original new statement, per BODS information updates / record identifiers modelling rules
- Robust country handling: emits a BODS
Country code only when a valid 2-letter ISO code resolves
Public API: map_psc_event, company_number_from_uri, parse_nature, describe_nature, PSC_NATURE_DESCRIPTIONS, country_object, statement factories (make_entity_statement, make_person_statement, make_relationship_statement), BODSBundle, stable_id, validate_shape
Requirements: Python ≥ 3.10, pycountry. MIT license (vendored CH nature descriptors under OGL v3.0).
opencheck
Type: Full customer due diligence (CDD) web application — LEI-powered, BODS v0.4 throughout.
Repo: https://github.com/StephenAbbott/opencheck
Live demo: https://opencheck.onrender.com/
OpenCheck is a comprehensive open-source CDD tool that uses the Legal Entity Identifier as a connector spine to fan out across 29 national and international corporate data sources, mapping everything to BODS v0.4. Currently at Phase 50 (50 phases of active development, 337+ commits).
How it works: paste a LEI → GLEIF lookup → derive every cross-source identifier available (Companies House number, Norwegian org number, Irish CRO, Finnish Y-tunnus, Latvian, Lithuanian, Estonian, Czech IČO, Polish KRS, Austrian Firmenbuchnummer, Slovak IČO, French SIREN, Dutch KvK, Swedish org number, Swiss UID, Canadian corp number, Belgian enterprise number, Danish CVR, Croatian MBS, Australian ACN/ABN, OpenCorporates ID, Wikidata Q-ID, and more) → fan out across all active adapters → assemble into a single BODS v0.4 bundle → apply risk signals → offer export.
National ID search (Phase 50): look up any company by local registration number (CH number, KvK, orgnr, CVR, SIREN, etc.) — queries GLEIF's three registration-ID filter fields in parallel, scoped to the RA code. Covers 17 countries with active adapters.
Risk signal layer (12 signals) — mirrors the EU AMLA draft CDD RTS conditions for "complex corporate structures":
- Source-derived signals (nominee, super-secure/opaque, sanctioned flag)
- AMLA CDD RTS signals (trust/arrangement, non-EU jurisdiction, ≥3 ownership layers, composite threshold rule, subjective obfuscation advisory)
- FATF jurisdiction (black/grey list)
- Cross-source name match discrepancies
- ICIJ Offshore Leaks match
Export formats: JSON / JSONL / XML / ZIP (downloaded bundle includes LICENSES.md listing every contributing source).
Architecture: FastAPI backend (Python 63%) + React/TypeScript frontend, cache-first dispatch (stub mode without API keys, live mode opt-in per source via env vars). Uses bods-dagre for BOVS ownership diagrams and bods-mapper for CH PSC → BODS mapping.
Roadmap: live opentender.eu procurement integration; BODS RDF/SPARQL backbone via Oxigraph (load assembled BODS bundle into triple store, expose /sparql for Open Ownership red-flag queries).
bods-gql
Conversion: BODS 0.4 → Google BigQuery property graph, queryable with GQL (ISO/IEC 39075).
Repo: https://github.com/StephenAbbott/bods-gql
GQL (ISO/IEC 39075) is the international standard graph query language adopted in April 2024. It uses pattern-matching syntax similar to Cypher but with different syntax for quantified paths and aggregation. BigQuery now supports GQL for property graph queries.
Output:
- Node tables: entity and person nodes with names, jurisdictions, and identifiers
- Edge tables: ownership interest relationships with stake percentages
- Property graph DDL:
CREATE PROPERTY GRAPH statements via graph_schema/property_graph.py
Includes 14 pre-built GQL queries across three modules covering UBO detection, corporate group mapping, and circular ownership analysis. 59 tests. Demonstrated with public BigQuery datasets containing GLEIF and UK Companies House beneficial ownership data.
CLI: cli.py | Input: BODS v0.4 JSON/JSONL | Output: BigQuery CSV tables + GQL schema.
GLEIF Level 1 & 2 Data → BODS 0.4
The Global Legal Entity Identifier Foundation (GLEIF) publishes two levels of open data for the 2.6M+ entities holding a Legal Entity Identifier (LEI):
- Level 1 (LEI-CDF): Entity identity data — legal name, registered address, jurisdiction, entity status, entity type, registration dates
- Level 2 (RR-CDF — Relationship Records): Ownership relationships between LEI holders — parent/subsidiary links, percentage ownership, relationship status, and dates
- Level 2 (Reporting Exceptions): Cases where an LEI holder cannot or will not report their direct/ultimate parent — with a stated reason code
GLEIF → BODS 0.4 mapping
| GLEIF data | BODS statement type |
|---|
| Level 1: LEI-CDF record | Entity statement |
| Level 2: Relationship Record (RR-CDF) | Ownership-or-control statement |
| Level 2: Reporting Exception | Entity, Person, or OOC statement (depending on exception type) |
The bods-gleif-pipeline (https://github.com/openownership/bods-gleif-pipeline) is the reference implementation. It runs on AWS (Kinesis data streams for pipeline stages, Elasticsearch for persistence between runs, EC2 for compute). The raw GLEIF concatenated files are 8GB+ uncompressed.
GLEIF was the first dataset published in BODS 0.4, making it the reference example for temporal change tracking with replacesStatements and the isComponent pattern.
Key mapping decisions in the BODS 0.4 update:
- Reporting Exceptions are now modelled as BODS statements (rather than being dropped), allowing the reason for non-disclosure to be captured
- Temporal lifecycle of LEI data changes is represented via
replacesStatements links rather than overwriting
Published data: https://bods-data.openownership.org/source/gleif_version_0_4/
OpenOwnership news release: https://www.openownership.org/en/news/global-legal-entity-ownership-data-available-in-line-with-latest-version-of-data-standard/
Mapping blog post: https://www.openownership.org/en/blog/updating-our-mapping-of-gleif-data-to-bods-to-better-capture-the-lifecycle-of-lei-data-changes/
Corporate Ownership Data Sources: Background Reference
These are sources useful for mapping work or for contextualising BO data. Fetch live documentation for precise field-level detail.
Sayari
A corporate intelligence platform covering 450M+ entities from 700+ sources across 250+ jurisdictions, with 2B+ ownership and control records. Sayari applies entity resolution to link records across sources, generating possibly-same-as relationships where confidence is insufficient to fully merge. Coverage includes parent-subsidiary, shareholder, and beneficial ownership structures. Particularly strong on hard-to-access jurisdictions.
OpenCorporates
The world's largest open company database (200M+ companies). Offers four relationship types in its Relationships File/Supplement: control_statement, subsidiary, branch, share_parcel. The Relationships Supplement has 30M+ relationships from primary sources (SEC, UK Companies House, etc.) and is separately licensed from the company data. Also provides person-with-significant-control and beneficial_owner flags. The API (v0.4.8) exposes companies, officers, and relationships.
BrightQuery / OpenData.org
BrightQuery (founded OpenData.org) provides government-sourced corporate data on 324M organisations, 512M locations, and 1.2B contacts across 222 countries. Data is structured around three core data dictionaries: organisations, locations, and people-business relationships. Key differentiator: comprehensive reference ID crosswalks (LEI, CIK, ISIN, NPI, PermID, OpenFIGI, SAM UEI, PlaceKey, OSM ID, etc.) and corporate family/hierarchy structures. OpenData.org was built with Senzing AI for entity resolution and positions itself as a consortium-governed open data platform.
InfobelPro
A global company data provider with 375M companies across 220 countries, sourcing data from 1,100+ official registries, tax authorities, and regulated filings. Provides 460+ firmographic, hierarchical, and technographic attributes per record, including ownership links and up to 8 years of historical records. Claims to trace every record to an official source (not aggregators or web scrapes). GDPR/CCPA compliant with stable entity IDs and standardised delivery across 200+ markets.
OECD-UNSD Multinational Enterprise Information Platform (MEIP)
A joint OECD/UN Statistics Division initiative tracking the 500 largest MNEs globally. The platform comprises a Global Register (subsidiary ownership structures and geographic footprint), a web presence register, and a media monitor. The 2024 data release (covering data as of 31 December 2024) added financial data (employees, revenue, net profit, R&D) extracted via AI from company filings and annual reports. Structured as an interactive dashboard with downloadable XLSX.
This is a useful reference dataset for mapping MNE corporate group structures to BODS, and for validating coverage of other corporate data sources.
BODS Interoperability: Mappings to Other Data Models
FollowTheMoney (FtM) / OpenSanctions
FollowTheMoney (FtM) is the data model used by OpenSanctions and the broader Aleph investigative data ecosystem. It represents persons, companies, assets, relationships, and documents in a property graph format designed for investigative and compliance work.
bods-ftm — there are two distinct repos with this name:
The OpenOwnership dataset on OpenSanctions (https://www.opensanctions.org/datasets/openownership/) republishes OpenOwnership BODS data in FtM format, making it available for cross-dataset analysis alongside sanctions lists, PEPs data, and company registries.
Practical use: BODS data in FtM format can be combined with OpenSanctions sanctions data and public procurement data (Open Contracting Data Standard) for cross-dataset risk detection. The OpenScreening proof-of-concept built on this approach matches beneficial owners to sanctions names via a graph database.
Senzing sz-semantics / RDF
The Senzing sz-semantics namespace (https://github.com/senzing-garage/sz-semantics/wiki/ns) defines an RDF Metadata Application Profile for representing entity resolution results as a knowledge graph. It explicitly aligns with BODS, NIEM, and FollowTheMoney as "popular controlled vocabularies used by Senzing partners."
The namespace provides:
sz:Entity — resolved entity (top-level concept)
sz:Person, sz:Organization — entity subtypes
sz:DataRecord — source records contributing to entity resolution
sz:member_of — relationship predicate applicable to ownership/membership
This is relevant when combining BODS data with Senzing entity resolution output, or when building linked data representations that need to align BODS concepts with Senzing's resolved-entity model. The OpenData.org platform (BrightQuery) was built using Senzing AI for entity resolution.
Developer workflows
Validating BODS data
Use CoVE-BODS web tool: https://datareview.openownership.org
Or use lib-cove-bods from the command line:
pip install lib-cove-bods
libcovebods your-data.json
Checks: required fields, valid enums, internal reference integrity, version compliance (0.1–0.4).
bods-validator — an alternative online validation and visualisation tool for BODS v0.4 data:
Repo: https://github.com/StephenAbbott/bods-validator
Built with FastAPI (backend) and React/TypeScript (frontend). Performs two layers of validation:
- JSON schema compliance checks against BODS v0.4 schema
- 26 additional regulatory compliance assessments via lib-cove-bods
Three input methods: direct JSON paste, file upload, or URL retrieval. Outputs validation results with actionable guidance, interactive ownership visualisations using BOVS design conventions, and side-by-side comparisons of national data formats mapped to BODS standards. Includes example datasets from UK, France, Indonesia, and Norway.
Testing BODS implementations
Two companion packages provide a shared, canonical fixture suite for testing any tool that ingests, transforms, or emits BODS v0.4 statements:
bods-fixtures — the fixture data pack:
- Repo: https://github.com/StephenAbbott/bods-fixtures
- PyPI: https://pypi.org/project/bods-v04-fixtures/ (
pip install bods-v04-fixtures)
- Provides small, curated BODS v0.4 statement bundles targeting specific semantic edge cases, each paired with a
.expected.md specification file describing correct adapter/query engine behaviour
- Current coverage (v0.1.1): direct ownership, circular ownership, anonymous persons
- Import:
from bods_fixtures import load, list_cases
- Acts as "the single source of truth" for fixtures across the BODS adapter ecosystem — ensures an entity observed in two sources produces equivalent BODS output
pytest-bods-fixtures — pytest plugin wrapping the data pack:
Both packages require Python ≥ 3.9. Fixture content is licensed CC-BY-SA 4.0; code is MIT.
Processing BODS data into flat formats
bodsdata (https://github.com/openownership/bodsdata) converts BODS JSON to:
- CSV / TSV
- SQLite
- Parquet
- PostgreSQL dump
It also runs consistency checks (required fields, duplicate statement IDs, broken internal references) and supports pandas/polars dataframe workflows. Use it when you need to load BODS data into a database or do tabular analysis.
BODSKit (https://bodskit.readthedocs.io) is a newer CLI suite with similar goals — worth checking for the latest capabilities.
Analysing BODS data in Python (notebooks)
bodsanalysis (https://github.com/openownership/bodsanalysis) provides:
qbods.py: functions for reading, summarising and analysing BODS 0.2 data
- Jupyter notebooks:
latvia_demo.ipynb (Latvia register), Insights_UK_PSC_BODS-02.ipynb (UK People with Significant Control)
- Runs on local Jupyter, Deepnote, or Google Colab
Note: the notebooks currently target BODS 0.2. For 0.4 data, adapt the field names (especially for isComponent and statement references).
Beneficial Ownership Visualisation System (BOVS)
The Beneficial Ownership Visualisation System (BOVS) is an OpenOwnership specification for how to illustrate beneficial ownership structures as clearly as possible.
URL: https://www.openownership.org/en/publications/beneficial-ownership-visualisation-system/
BOVS defines the rules for drawing BOVS Diagrams — a standardised visual language for representing ownership and control structures. Key characteristics:
- Compatible with any brand, style, colour scheme, or language
- Published under the GNU Free Documentation License (free to use by anyone building BO visualisations)
- Designed to help implementers choose how to represent different aspects of ownership — direct vs. indirect interests, unknown intermediaries, control vs. ownership, etc.
- Offered to anyone building visualisations of beneficial ownership structures, not just BODS users
BODS Visualisation Library — the BODS-specific implementation of BOVS:
URL: https://www.openownership.org/en/publications/beneficial-ownership-data-standard-visualisation-library/
The BODS Visualisation Library bakes many of the BOVS rules into a reusable library designed for rendering BODS-structured data. It is already in production use in the official beneficial ownership registers of Armenia, Bermuda, and Botswana.
The bods-dagre npm package (see below) is the developer-facing tool that implements this library.
Visualising ownership graphs
visualisation-tool / bods-dagre turns BODS JSON into directed graph diagrams.
Input: a JSON array of BODS statements (person, entity, ownership-or-control).
Output: SVG/canvas network diagram with:
- Person nodes (name, nationality flag, person-type icon)
- Entity nodes (name, jurisdiction flag, entity-type icon, public company indicator)
- Directed edges showing ownership/control relationships
npm package: @openownership/bods-dagre
npm install @openownership/bods-dagre
The tool handles temporal data — it filters to a snapshot at a given point in time when multiple versions of records exist. See the full spec at https://github.com/openownership/visualisation-tool/blob/main/docs/spec.md.
Neo4j Graph Database: UK Companies House UBO Analysis
Graph databases are a natural fit for beneficial ownership data — ownership chains, loops, and ultimate parent traversal are graph problems that relational databases handle poorly. Two resources demonstrate this with UK data:
Neo4j developer guide — Company Ownership & UBO Graphs
URL: https://neo4j.com/developer/industry-use-cases/finserv/retail-banking/company-ownership-ubo-graphs/
Covers the conceptual case for graph technology for UBO analysis in financial services (retail banking context). Explains variable-length path traversal for finding ultimate beneficial owners, and introduces the UK PSC dataset as a practical source.
erikbijl/neo4j-company-house-demo
Repo: https://github.com/erikbijl/neo4j-company-house-demo
Webinar recording: https://go.neo4j.com/WBREDU260210FinServ_On-Demand.html
A working implementation using UK Companies House open data (snapshots from January 2026):
- Data sources: Companies House Company Data Product + PSC Data Product
- Graph model: five node types (Company, LegalEntity, Individual, Address, SIC-code) with three relationship types (OWNS, REGISTERED_AT, HAS_SIC)
- Key notebooks:
company_house_companies.ipynb (loads company/address/SIC data) and company_house_psc.ipynb (processes PSC ownership relationships)
- Includes: pre-built Neo4j dashboard (Company_Profile_Dashboard_2026-03-31.json) and a database backup via Google Drive
- Enables variable-length ownership traversal, root entity identification, and detection of circular ownership structures
GraphAware Hume platform: BODS data + graph technology for UBO investigations
Blog/event page: https://www.openownership.org/en/blog/join-our-event-master-complex-ubo-investigations-with-advanced-graph-technology/
YouTube recording: https://www.youtube.com/watch?v=BO6TVN5UL14
A webinar co-presented with Stephen Abbott Pugh showing how BODS-structured beneficial ownership data can be used alongside other data types in GraphAware's Hume platform (powered by Neo4j). Hume is a graph-based investigation platform used in financial crime, compliance, and investigative journalism contexts. The session demonstrated how BODS data integrates with Hume's entity resolution and link analysis capabilities for complex UBO investigations.
Relationship to BODS: The neo4j-company-house-demo uses UK PSC data directly rather than BODS JSON, but the graph model (person/entity nodes + ownership edges) closely mirrors the BODS statement model. BODS data — which standardises this structure across jurisdictions — maps naturally onto Neo4j's property graph model and would enable cross-jurisdictional UBO traversal in a single graph.
Generating test / sample BODS data
The BODS data generator is a Google Sheets template that lets anyone produce valid BODS JSON without writing code. It's the fastest way to create test data or demonstrate the standard to non-technical audiences.
The sheet has three tabs mirroring the three BODS statement types:
1_person_main — person statement data
2_entity_main — entity statement data
3_ownership_control_main — ownership-or-control statement data
Output: paste from the Upload sheet into CoVE-BODS for validation and JSON download. Can also feed directly into the bods-dagre visualiser.
Note: the generator currently targets BODS 0.3. For 0.4 you may need to adjust output for isComponent and componentStatementIDs fields.
Working with BODS as Linked Data / RDF
bodsld (https://github.com/openownership/bodsld) provides:
Note: bodsld maps the BODS schema to RDF vocabulary — it does not convert BODS instance data to RDF triples. If you need to convert actual BODS records to RDF, you'll need to write a custom transformation.
Common patterns and gotchas
Resolving references: Ownership-or-control statements reference persons and entities by statementId. When loading data, build a lookup dict keyed by statementId first, then resolve references.
Indirect ownership chains: In BODS 0.4, isComponent: true marks statements that are part of an indirect chain. The top-level statement uses componentStatementIDs to list the supporting component statements.
Temporal data: The same real-world entity may have multiple statements over time. To get the current picture, filter to the most recent statement for each statementId group (using replacesStatements).
Version detection: Check publicationDetails.bodsVersion to know which version of BODS the data conforms to. Field names and required properties differ between 0.2, 0.3, and 0.4.