> ## 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.

# Discrepancy Reports

> Report a beneficial-ownership discrepancy to the register, from the API

> [!NOTE]
>
> **Beta.** Discrepancy reports are available in Germany only for now, and we will extend coverage to more countries soon. The request and response shapes may still change. Access is enabled per account with a subscription that includes a monthly allowance of reports: contact [support@topograph.co](mailto:support@topograph.co) to request it. If you need another country, tell us at the same address: we are looking for teams to shape the next registers with.

As an obliged entity, you must report to a beneficial-ownership register any discrepancy between what the register lists and what your own due diligence established. Each country has its own register and its own reporting form.

`POST /v2/discrepancy-reports` files that report for you, with one request shape for every country. You send the beneficial owners you identified in the same shape you receive them from [`POST /v2/company`](https://docs.topograph.co/essentials/retrieve_company). We write the explanation in the register's language, file the report under your own register account, keep the register's acknowledgement of receipt, and tell you the outcome by webhook or polling.

All examples on this page use fictitious data.

## Before you start

1. **Access.** The beta must be enabled on your account. Without it, every call answers `403` with `feature_not_enabled`.
2. **Your register credentials, on a workspace.** See [Register credentials and workspaces](#register-credentials-and-workspaces) below.
3. **Your allowance.** Your subscription allows a number of reports per monthly period. Once they are used up, a report answers `429` with `quota_exceeded`. `GET /v2/discrepancy-reports/usage` shows the limit, what is used and when the allowance renews. Reports that fail are not counted.

## Register credentials and workspaces

The duty to report is yours, so every report is filed under your own account at the register, never under Topograph's. The register records you as the reporter, and the report appears in your account there.

You store that account's credentials on a [workspace](https://docs.topograph.co/essentials/workspaces.md), once per register, through the vault:

```bash theme={null}
curl -X PUT https://api.topograph.co/v2/workspaces/compliance/vault/de_transparenzregister \
  -H "x-api-key: $TOPOGRAPH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "payload": { "email": "kyc@example.com", "password": "…" } }'
```

The credential key names the register (`de_transparenzregister` for Germany, see [Supported countries](#supported-countries)). Credentials are encrypted at rest, never returned by the API, and used only to file and follow your reports. See [Register credentials](https://docs.topograph.co/essentials/register-credentials.md) for how they are stored.

When you file a report, the workspace decides which credentials are used:

1. The workspace you select with the `x-topograph-workspace-id` header, if it holds credentials for that country's register.
2. Otherwise, those of your account's default workspace.
3. Otherwise, the report is refused with `428` `account_configuration_required`, and nothing is filed.

So if several legal entities of your group report separately, give each its own workspace with its own register account, and send each report from the right workspace. A report always stays with the workspace that filed it: it is followed and its receipt fetched with the same credentials.

If the register rejects the stored credentials, the report fails with `account_configuration_required` and nothing is filed. Update them on the workspace and send the report again with a new `Idempotency-Key`.

## File a report

```bash theme={null}
curl -X POST https://api.topograph.co/v2/discrepancy-reports \
  -H "x-api-key: $TOPOGRAPH_API_KEY" \
  -H "x-topograph-workspace-id: compliance" \
  -H "Idempotency-Key: 5b0e2c1a-6d1f-4a7e-9c3b-2f8e1d0a9b7c" \
  -H "Content-Type: application/json" \
  -d '{
    "countryCode": "DE",
    "companyId": "München HRB 228960",
    "reasons": ["incorrect_or_incomplete_information"],
    "ultimateBeneficialOwners": [{
      "gender": "Female",
      "name": { "fullName": "Erika Mustermann", "firstName": "Erika", "lastName": "Mustermann" },
      "control": {
        "types": ["ownership-of-shares"],
        "details": [{ "type": "shares", "percentageValue": 100 }]
      }
    }],
    "evidence": { "type": "public_register_reference" },
    "attestation": { "accepted": true },
    "metadata": { "caseId": "case-12345" }
  }'
```

| Field | What to send |
| - | - |
| `countryCode`, `companyId` | The company, with the same ID you use for `POST /v2/company`. We resolve the register's own identifiers and file only on an exact, active match. |
| `reasons` | `incorrect_or_incomplete_information`: details of a registered beneficial owner are wrong or incomplete. `different_beneficial_owners`: you identified different beneficial owners. Send one or both. New values may be added; tolerate ones you do not know. |
| `ultimateBeneficialOwners` | The beneficial owners as the register should list them, in the shape of `ultimateBeneficialOwners` in the company response: `name`, `gender`, `birthDate`, `nationality`, `residenceAddress`, `control`. You can send back an entry you received, corrected; fields a report does not use, such as `entityId`, are ignored. |
| `evidence` | `{ "type": "public_register_reference" }`: the discrepancy can be established from public registers. Uploading your own documents will be added. |
| `attestation` | `{ "accepted": true }`, required. It stands for the register's declaration: you compared the entry with the information you hold, you determined the beneficial owners as the law requires, and you are entitled to report. |
| `comment` | Optional free text appended to the explanation, in the register's language. |
| `sourceRequestId` | Optional: the `requestId` of the company request that showed the register data you dispute. |
| `metadata` | Optional key-value strings, echoed in every response and webhook. |

> [!WARNING]
>
> The report is filed as soon as it is accepted. There is no draft step: validate on your side before you send it.

### The explanation we file

The explanation is written in the register's language, from the facts you send and only from them. The response shows it in `filing.text` from the moment the report is accepted. For the German example above:

```text theme={null}
Die wirtschaftlich Berechtigte ist Erika Mustermann mit 100 %.
```

Percentages come from `control.details`. When you have not established a percentage, omit `details`: none is ever assumed. Where the language has grammatical gender, as German does, `gender` decides the form. Each register limits the length of the explanation; a longer one is refused with `400` before anything is filed.

## Follow the report

`POST` answers `201` with `status: "in_progress"`. Filing usually takes under two minutes.

| `status` | Meaning |
| - | - |
| `in_progress` | Accepted and being filed. It can stay in this state longer while the register is unavailable. Do not resend it. |
| `succeeded` | Filed. `filing.registerReference` is the register's report number and `filing.receipt` its acknowledgement of receipt. |
| `failed` | Nothing was filed. `error.code` and `error.message` say why. Correct the request and send it again with a new `Idempotency-Key`. |

You learn the outcome in either of two ways:

* **Webhook.** [`discrepancy_report.updated`](https://docs.topograph.co/guides/webhooks) carries the report exactly as `GET` returns it.
* **Polling.** `GET /v2/discrepancy-reports/{id}` is free. `GET /v2/discrepancy-reports` lists your reports, filtered by `companyId`, `countryCode` or `status`, with `first` and `after` for pagination.

### The receipt

`filing.receipt.url` downloads the register's acknowledgement of receipt as a PDF. The link is valid for 15 minutes; fetch the report again for a fresh one. `filing.receipt.sha256` identifies the file, so you can prove later that a stored copy is the one received. We keep the receipt after the register stops serving it.

A receipt confirms that the register received your report. It is not the register's decision on the discrepancy.

## Retries and idempotency

`Idempotency-Key` is required, and a UUID per report is recommended. Sending the same body again with the same key returns the original report with `200` and files nothing new, so a request that timed out on your side is safe to resend as is. Reusing a key with a different body answers `409`.

A report is filed at most once, whatever happens in between. If we cannot confirm right away whether the register received a report, it stays `in_progress` while we check with the register; it is never filed a second time.

## Errors

| Code | HTTP | When |
| - | - | - |
| `invalid_request` | 400 | A field is missing or invalid, the country is not supported yet, or the explanation is too long. Also `409` for a reused `Idempotency-Key`. |
| `feature_not_enabled` | 403 | The beta is not enabled on your account. |
| `account_configuration_required` | 428 | No register credentials on the workspace or its default, or the register rejected them. |
| `quota_exceeded` | 429 | Your allowance for the period is used up. |
| `resource_not_found` | on the report | The register holds no active company under this ID. |
| `source_unavailable` | on the report | The register stayed unavailable for a day. Nothing was filed. |

Errors found before the report is accepted are returned by `POST`. Errors found while filing appear on the report as `status: "failed"` with `error`. See [Reliability and errors](https://docs.topograph.co/guides/reliability-and-errors.md) for the full list.

## Supported countries

| Country | Register | Credential key | Explanation | Evidence |
| - | - | - | - | - |
| 🇩🇪 Germany (`DE`) | Transparenzregister | `de_transparenzregister`: the account's email and password | German, up to 1,000 characters | `public_register_reference` (§ 22 GwG) |

In Germany, the report is an *Unstimmigkeitsmeldung* under § 23a GwG. `incorrect_or_incomplete_information` is filed as "Angaben nach § 19 Abs. 1 GwG sind fehlerhaft/unvollständig", and `different_beneficial_owners` as "Abweichende Liste wirtschaftlich Berechtigter wurde ermittelt". The Transparenzregister account must be allowed to file discrepancy reports.

More countries are coming, with the same request and response shapes.

## Test in your development environment

A [development environment](https://docs.topograph.co/guides/development-environment.md) accepts the same requests without register credentials and files nothing. It generates a register reference and a receipt PDF marked as a sandbox artefact, and sends the real `discrepancy_report.updated` webhook. Put a test identifier in `companyId` to force an outcome: any public error code in upper case, such as `RESOURCE_NOT_FOUND`, `SOURCE_UNAVAILABLE`, `ACCOUNT_CONFIGURATION_REQUIRED` or `QUOTA_EXCEEDED`, or a delay such as `DELAY_1M`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.