/v2/company endpoint is the single entry point for company data, official documents, and ownership graph traversal. It accepts one company identifier, one country, and the datapoints or documents you want.
Use it for company onboarding, KYB verification, shareholder and UBO checks, subsidiary analysis, official document retrieval, and follow-up polling by requestId.
For live country coverage, data block availability, pricing, sources, identifiers, and document catalogs, see Coverage and pricing.
Request shape
Datapoints
Availability varies by country and mode. Use the live pricing pages orGET /v2/pricing for country-specific availability.
The legacy
companyProfile datapoint is still accepted for existing integrations. New integrations should request explicit datapoints. See the migration guide.
Legal Entity Identifier (LEI)
Thecompany datapoint includes company.identifiers.lei when a company identifier uniquely matches a registration or validation reference in the GLEIF database. Existing country identifiers remain available alongside it.
Coverage varies by jurisdiction and entity. The field is absent when there is no unambiguous identifier match; absence does not prove that the company has no LEI. Lapsed and retired LEIs may be returned, while annulled LEIs are excluded.
Person identities and role entries
entityId identifies a person or company within a request. It links occurrences of the same entity across datapoints, such as legalRepresentatives, shareholders, and ultimateBeneficialOwners. It is not a permanent identifier to match people across separate requests.
An entityId can appear more than once in legalRepresentatives. A person holding several roles can have a separate entry for each appointment, with the same entityId and different role details or appointment dates.
For example, a Belgian director can also be a member of the management committee:
To import one record per person, group entries by
entityId within the request and retain all associated roles and appointment dates. Neither entityId alone nor the combination of entityId and role.standardized is a unique key for a role entry. Different local roles can share a standardized category. If entityId is absent, do not group all entries without an ID into one person.
Choose a mode
/v2/company supports two modes:
- Verification mode is the default and prioritizes authoritative data for compliance.
- Prefill mode (
mode: "prefill") prioritizes speed for form prefill and early screening.
Documents
Document retrieval is a two-step flow:- Request
availableDocuments. - Pass selected document IDs in the
documentsarray.
availableDocuments before requesting a download. See Document retrieval.
Response lifecycle
Every request returns arequest object with the current status of each datapoint and document.
The response may be progressive. For example,
company can succeed before legalRepresentatives, documents, or ownership datapoints finish.
Not every failed is an outage
These error.code values mean the datapoint is not something we return for this
request, rather than something that went wrong:
All of them carry
retryable: false: the same request gets the same answer. Handle them the way you would handle a successful
“nothing to report” answer: don’t retry, don’t alert, don’t block your flow waiting
for them. Filter on the code or on retryable. error.message is human-readable and
safe to show your own users. The complete list of codes, with retryable and the
recommended retryAfterSeconds for the ones you can resubmit, is in
Reliability & Errors.
To know which datapoints a country returns before you request them, see
Coverage and pricing or GET /v2/pricing.
An empty list is an answer
The list-shaped fields —legalRepresentatives, otherKeyPersons,
establishments, shareholders, subsidiaries, ultimateBeneficialOwners —
follow one rule, in both the API response and the webhook payload:
So a datapoint whose
dataStatus says succeeded always carries its list. You
never have to disambiguate “succeeded with nothing attached” from “never ran” —
succeeded plus a missing key cannot happen.
An empty list means the register holds no such record, which is not always
the same as the entity has none. Some registers only publish part of a
category: the Dutch KVK, for example, registers a shareholder only when a
company has a single 100% holder, so a BV with several shareholders returns
shareholders: []. Country pages document these limits — see
Netherlands.Polling
Use therequestId to fetch the latest result. This is free and does not create a new billable request.
succeeded or failed). In production, use webhooks when possible.
Some datapoints are manually delivered and stay
in_progress for typically 1–3 business days. For these, webhooks are strongly recommended over polling.succeeded or failed will hang if a new
intermediate status is ever introduced.
PDF extract
Any request can also be returned as a single-file PDF extract, suitable for attaching to a case file or handing to a reviewer.Requesting before a request has finished
By default the extract renders whatever has arrived, exactly asGET /v2/company/{requestId} returns partial results while a request is still running.
The extract is built around the company datapoint, so it needs company data to render anything. Until company has arrived, the endpoint returns 409 with extract_data_incomplete, even without requireComplete. If the request settles without company data (because company was not requested, or it failed), it returns 409 with extract_no_data. Include company in any request you want an extract for.
A partial extract says so on its own face, so it can never be mistaken for a complete one:
- The seal reads PARTIAL instead of VERIFIED.
- A Data completeness section lists every requested datapoint and whether it was included, is still being retrieved, or failed — with the reason.
- The
X-Topograph-Data-Statusresponse header carriescompleteorpartial, so you can branch without opening the file.
requireComplete:
409 while any requested datapoint is still running, naming what it is waiting on:
Only datapoints decide completeness. Documents are delivered as separate files and never appear in the extract, so a document still downloading does not hold the PDF back.
Seal states
Viewing in a browser
The response defaults toContent-Disposition: attachment. Pass disposition=inline to render it in place instead: