> ## Documentation Index
> Fetch the complete documentation index at: https://docs.topograph.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating to the Data Product Model

> Move from companyProfile and /v2/onboarding to granular datapoints on /v2/company

Historically, `/v2/company` accepted a single catch-all datapoint called `companyProfile` and onboarding ran on its own `/v2/onboarding` endpoint. That model hid what you were actually buying (one `companyProfile` meant different things in different countries) and forced onboarding and verification down two separate code paths.

The Data Product Model replaces `companyProfile` with explicit, named datapoints and folds `/v2/onboarding` into `/v2/company` as a `mode`. You now ask for exactly the sections you need, the billing and response shape match what you requested, and both retrieval modes share the same endpoint.

Both legacy shapes still work. This guide shows you how to move over.

## The datapoints

A request to `POST /v2/company` takes a `dataPoints` array. Each entry is one of the values below. Availability varies by country (see each [country guide](/essentials/france)).

| Datapoint                  | What you get                                                                                                                                                   |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `company`                  | Core registration record: legal name, registration number, legal form, status, incorporation date, registered address, share capital, activity codes, tax IDs. |
| `legalRepresentatives`     | Directors, managers, and officers with signing authority.                                                                                                      |
| `otherKeyPersons`          | Non-signing roles the register exposes separately: auditors, supervisory board members, commissaires aux comptes, etc.                                         |
| `establishments`           | Branches and secondary locations with their own address and local registration number.                                                                         |
| `shareholders`             | Direct shareholders and their ownership percentages, as declared at the register.                                                                              |
| `ultimateBeneficialOwners` | UBO declarations: natural persons with ultimate control, ownership chain, and control type.                                                                    |
| `availableDocuments`       | List of official documents the register exposes for this company. Always free. Use the returned IDs in a follow-up `documents` request.                        |
| `graph`                    | Ownership and control network: nodes (companies, people) and edges (shareholding, subsidiaries, officer roles). Budget-capped with `graphMaxBudget`.           |

<Info>
  `company`, `legalRepresentatives`, `otherKeyPersons`, and `establishments` are the datapoints introduced by the Data Product Model. `shareholders`, `ultimateBeneficialOwners`, `availableDocuments`, and `graph` pre-date it and have always been callable by name.
</Info>

### What `companyProfile` means

`companyProfile` is a legacy alias. It stands for **`company` + `legalRepresentatives` + `otherKeyPersons` + `establishments`**, on a best-effort basis.

**Best-effort** means: each of the four expanded datapoints is included only if the country has a block covering it in the mode you requested. If a datapoint has no compatible block, it is silently dropped from the expansion. You are never billed for datapoints the country cannot deliver.

Concretely:

| Country            | Verification block covers                         | `companyProfile` expansion in verification                   |
| ------------------ | ------------------------------------------------- | ------------------------------------------------------------ |
| FR, GB, BE, CZ     | all 4                                             | all 4                                                        |
| EE                 | company, legalReps, otherKeyPersons, shareholders | company, legalReps, otherKeyPersons (establishments dropped) |
| DK                 | company, legalReps, establishments, shareholders  | company, legalReps, establishments (otherKeyPersons dropped) |
| DE, IT, ES, AT, CY | company, legalReps                                | company, legalReps only                                      |

The same rule applies in onboarding mode: the expansion is filtered against the country's fast block. For Italy this means `companyProfile` in onboarding mode includes `otherKeyPersons` (the fast block covers it) but `establishments` is still dropped.

Billing is one block per resolved bundle. Expansion never adds a separate catalog item.

## Replace `companyProfile`

Swap `companyProfile` for the datapoints you actually need.

```json theme={null}
// Before
{ "dataPoints": ["companyProfile"] }

// After (equivalent on countries whose block covers all four)
{ "dataPoints": ["company", "legalRepresentatives", "otherKeyPersons", "establishments"] }

// After (when you only need the basics)
{ "dataPoints": ["company", "legalRepresentatives"] }
```

Pick the names you consume:

* `company` alone if you only need the registration record.
* `company` + `legalRepresentatives` for the classic KYB pair.
* Add `otherKeyPersons` when your compliance checks cover auditors or board members without signing authority.
* Add `establishments` when you need branch offices.
* Add `shareholders` / `ultimateBeneficialOwners` for ownership checks.

Explicit names make your billing predictable and your response shape visible to the reader of the code.

### Do not mix legacy and new names

Within one request, you must pick one vocabulary:

* Legal: `["companyProfile"]`, `["companyProfile", "shareholders"]`, `["companyProfile", "ultimateBeneficialOwners", "availableDocuments"]`
* Legal: `["company", "legalRepresentatives"]`, `["company", "shareholders", "ultimateBeneficialOwners"]`
* **Rejected with HTTP 400**: `["companyProfile", "company"]`, `["companyProfile", "legalRepresentatives"]`, `["companyProfile", "otherKeyPersons"]`, `["companyProfile", "establishments"]`

The rule is: `companyProfile` cannot appear alongside any of the four new names (`company`, `legalRepresentatives`, `otherKeyPersons`, `establishments`). Shared datapoints (`shareholders`, `ultimateBeneficialOwners`, `availableDocuments`, `graph`) can be combined with either vocabulary.

### The response echoes your vocabulary

`dataStatus.dataPoints` uses the exact keys you sent. Send `companyProfile`, get `companyProfile` back. Send `company` + `legalRepresentatives`, get them back separately. The internal best-effort expansion is not visible in `dataStatus`.

```json theme={null}
// Request: { "dataPoints": ["companyProfile"] }
{
  "dataStatus": {
    "dataPoints": {
      "companyProfile": { "status": "succeeded" }
    }
  }
}

// Request: { "dataPoints": ["company", "legalRepresentatives"] }
{
  "dataStatus": {
    "dataPoints": {
      "company": { "status": "succeeded" },
      "legalRepresentatives": { "status": "succeeded" }
    }
  }
}
```

This is why existing integrations keep working unchanged.

The response body itself contains whatever sections the country's block produced. For a country whose block covers all four company-level datapoints, a `companyProfile` request returns `company`, `legalRepresentatives`, `otherKeyPersons`, and `establishments` fields in the body. Request them explicitly (new vocabulary) to make that shape obvious in your code.

## Replace `/v2/onboarding`

`/v2/onboarding` is deprecated. Use `/v2/company` with `mode: "onboarding"` instead.

```bash theme={null}
# Before
curl -X POST https://api.topograph.co/v2/onboarding \
  -H 'x-api-key: <key>' \
  -d '{
    "countryCode": "DE",
    "id": "HRB123456"
  }'

# After
curl -X POST https://api.topograph.co/v2/company \
  -H 'x-api-key: <key>' \
  -d '{
    "countryCode": "DE",
    "id": "HRB123456",
    "dataPoints": ["company", "legalRepresentatives"],
    "mode": "onboarding"
  }'
```

Two wins from the move:

1. You pick the datapoints. The old endpoint only ever returned the equivalent of `company` + `legalRepresentatives`. On `/v2/company` you can add `shareholders`, `ultimateBeneficialOwners`, or anything else and still run in onboarding mode.
2. One codebase, one response shape. Verification and onboarding share the endpoint, the DTO, and the `dataStatus` format. Read [Verification vs Onboarding Mode](/essentials/modes) for the source-selection and deadline behavior.

<Info>
  Onboarding mode enforces a hard 10-second deadline per datapoint and only uses fast sources. Datapoints that have no fast source fail with `fast_source_unavailable`. See [Verification vs Onboarding Mode](/essentials/modes).
</Info>

## Compatibility summary

| Legacy shape                          | Status                                                       | Replacement                                                                               |
| ------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| `dataPoints: ["companyProfile"]`      | Works (best-effort alias for the 4 company-level datapoints) | Explicit list: `["company", "legalRepresentatives", "otherKeyPersons", "establishments"]` |
| `POST /v2/onboarding`                 | Deprecated                                                   | `POST /v2/company` with `mode: "onboarding"`                                              |
| Deprecated `fast: true` flag          | Works                                                        | `mode: "onboarding"`                                                                      |
| Deprecated `authoritative: true` flag | Works                                                        | omit `mode` or pass `mode: "verification"`                                                |

New integrations should start with the new vocabulary and `/v2/company`. Existing integrations can stay on `companyProfile` and `/v2/onboarding` as long as needed, and migrate opportunistically.

## Next steps

<CardGroup cols={2}>
  <Card title="Company Data" icon="building" href="/essentials/retrieve_company">
    Full `/v2/company` request and response reference.
  </Card>

  <Card title="Verification vs Onboarding Mode" icon="bolt" href="/essentials/modes">
    Source selection, deadlines, and `authoritative` flag.
  </Card>

  <Card title="KYB Onboarding" icon="rocket" href="/guides/kyb-onboarding">
    End-to-end flow combining search, onboarding mode, and verification.
  </Card>

  <Card title="Pricing & Caching" icon="coins" href="/essentials/pricing-and-caching">
    How datapoints map to billable blocks and the 24-hour dedup window.
  </Card>
</CardGroup>
