Usage

All v2 functionality is exposed through GleifClient, importable as pygleif.GleifClient or pygleif.v2.GleifClient.

from pygleif import GleifClient

client = GleifClient()

Every method has an async counterpart prefixed with a (e.g. search / asearch, get_lei / aget_lei, fields / afields). Both share the same httpx-based Transport, so you can freely mix sync and async usage against the same client. See “Async usage” below.

Fetching a single LEI record

response = client.get_lei_record("549300MLUDYVRQOOXS22")

print(response.data.attributes.entity.legal_name.name)
# prints UK EQUITY FUND (OFFSHORE)

For a normalized, generation-agnostic view (a RecordLike), use get_lei instead:

record = client.get_lei("549300MLUDYVRQOOXS22")

print(record.lei, record.legal_name, record.country)

Searching

results = client.search_fulltext("Deutsche Bank")

for item in results.data:
    print(item.attributes.lei, item.attributes.entity.legal_name.name)

Look up records by BIC or ISIN:

client.by_bic("DEUTDEFFXXX")
client.by_isin("DE0005140008")

Or run an arbitrary filtered search with sorting and pagination:

from pygleif import SearchType

client.search(
    filters={SearchType.LEGAL_NAME: "Deutsche Bank"},
    sort="entity.legalName",
    page_number=1,
    page_size=15,
)

Filter operators

Filter values are passed through verbatim, so the API’s documented search operators work directly:

client.search(filters={"entity.legalAddress.country": "!GB"})       # NOT
client.search(filters={"entity.legalName": "facebook,twitter"})     # IN
client.search(filters={"entity.expiration.date": "19900101..19950101"})  # range
client.search(filters={"entity.expiration.date": ">=20190723"})     # comparison

Multiple filters combine as a logical AND. To find relationship data via search, use the owns (“who owns X?” — returns parents) and ownedBy (“who is owned by X?” — returns children) filters:

client.search(filters={"owns": "549300MLUDYVRQOOXS22"})
client.search(filters={"ownedBy": "549300MLUDYVRQOOXS22"})

Level 2 relationship data

Fetch parent and child LEI records through the dedicated relationship endpoints:

client.direct_parent("549300MLUDYVRQOOXS22")      # single LEI record
client.ultimate_parent("549300MLUDYVRQOOXS22")    # single LEI record
client.direct_children("549300MLUDYVRQOOXS22")    # paginated LEI records
client.ultimate_children("549300MLUDYVRQOOXS22")  # paginated LEI records

The relationship records themselves (reporting periods, corroboration, relationship status) are available too:

client.direct_parent_relationship("549300MLUDYVRQOOXS22")
client.ultimate_parent_relationship("549300MLUDYVRQOOXS22")
client.direct_child_relationships("549300MLUDYVRQOOXS22")
client.ultimate_child_relationships("549300MLUDYVRQOOXS22")

When an entity reports no parent, the parent lookups raise PyGLEIFNotFoundError and the reason is available as a reporting exception:

from pygleif.v2.error import PyGLEIFNotFoundError

try:
    client.direct_parent("9845001B2AD43E664E58")
except PyGLEIFNotFoundError:
    exception = client.direct_parent_reporting_exception("9845001B2AD43E664E58")
    print(exception.data.attributes.reason)  # e.g. NON_CONSOLIDATING

ultimate_parent_reporting_exception works the same way for the ultimate parent.

ISIN mappings

client.isins("549300MLUDYVRQOOXS22")

Field modifications (record history)

Retrieve the historical changes of an LEI record, optionally filtered:

client.field_modifications("549300MLUDYVRQOOXS22")
client.field_modifications(
    "549300MLUDYVRQOOXS22",
    modification_type="UPDATE",
    record_type="RR",
    page_size=50,
)

Completions and field metadata

client.fuzzy_completions("Deutche Bank")  # approximate matches, typo-tolerant
client.autocompletions("Deutsche")        # suggested search terms
client.fields()                           # technical metadata about API fields
client.get_field("LEIREC_FULLTEXT")       # metadata for one field

Both completion endpoints accept a field argument (fulltext, entity.legalName, owns, ownedBy — see SearchType).

LEI and vLEI issuers

client.lei_issuers()                                  # accredited LOUs
client.get_lei_issuer("5299000J2N45DDNE4Y28")         # one LOU by its LEI
client.lei_issuer_jurisdictions("5299000J2N45DDNE4Y28")
client.vlei_issuers()                                 # qualified vLEI issuers
client.get_vlei_issuer("549300O897ZC5H7CY412")

Reference data

Each code list has a paginated list method and a get_* detail lookup:

client.countries()                                # ISO 3166 country codes
client.get_country("US")
client.entity_legal_forms()                       # ISO 20275 ELF codes
client.get_entity_legal_form("10UR")
client.official_organizational_roles()            # ISO 5009 OOR codes
client.get_official_organizational_role("01D0O4")
client.jurisdictions()                            # legal jurisdictions
client.get_jurisdiction("US-DE")
client.regions()                                  # ISO 3166 sub-regions
client.get_region("AD-07")
client.registration_authorities()                 # GLEIF RA code list
client.get_registration_authority("RA000001")
client.registration_agents()
client.get_registration_agent("5d10d4dc929ab6.72309473")

Exporting LEI records

Download up to 5000 LEI records as a file (csv, xlsx or json), narrowed by the same filters as search:

from pygleif import ExportFormat

payload = client.export_lei_records(
    export_format=ExportFormat.CSV,
    filters={"entity.legalAddress.country": "SE"},
)
with open("lei-records.csv", "wb") as handle:
    handle.write(payload)

Health check

if not client.healthcheck():
    ...  # API is unreachable

Async usage

Every method described above has an a-prefixed async counterpart that takes the same arguments and returns the same response model:

import asyncio

from pygleif import GleifClient


async def main() -> None:
    async with GleifClient() as client:
        record = await client.aget_lei("549300MLUDYVRQOOXS22")
        results = await client.asearch_fulltext("Deutsche Bank")
        print(record.legal_name, len(results.data))


asyncio.run(main())

Using async with (or with for sync-only code) ensures the underlying httpx connection pool is closed when you’re done. Without a context manager, call client.close() or await client.aclose() explicitly:

client = GleifClient()
try:
    client.search_fulltext("Deutsche Bank")
finally:
    client.close()

Error handling

All v2 errors derive from PyGLEIFError:

from pygleif.v2.error import PyGLEIFNotFoundError, PyGLEIFRateLimitError

try:
    client.get_lei_record("does-not-exist")
except PyGLEIFNotFoundError:
    ...  # HTTP 404
except PyGLEIFRateLimitError:
    ...  # HTTP 429 - 60 requests/minute limit exceeded