# How to Confirm a Business Partner's Identity and Data Quality?

## Overview

This tutorial walks you through your first successful call to the **Confirm Business Partner** endpoint. You will submit a trading partner's name, address, and identifier, and learn how to read a response that answers a simple question: *is this trading partner who they claim to be, and is their data good enough to act on?*

Behind the scenes, the endpoint looks up the submitted data against reference sources, builds an enriched **golden record**, and compares it back against what you submitted. It orchestrates four CDQ products to produce one consolidated result:

| Product  | Role in confirmation |
|  --- | --- |
| Partner Guard | Cross-references company and address details against trusted reference sources and creates an enriched golden record. |
| Data Quality Guard | Applies data quality rules to the submitted data to ensure it is well-formed and consistent. |
| Tax Guard | Validates the submitted VAT/tax identifier against official tax registers (optional). |
| AML Guard | Screens the trading partner against sanction and watchlist data (optional). |


This makes the endpoint a good fit for onboarding checks, for example confirming a new customer or supplier before creating it in your system, instead of checking a company register, a VAT database, and a sanction list separately.

**Learning Goals**

In this tutorial, you will learn how to:

- Make your first request to the Confirm Business Partner endpoint
- Read the response structure and its four confirmation sections
- Interpret the overall confirmation decision and the status of individual attributes
- Enable the optional qualification and sanction checks
- Recognise and troubleshoot common error responses


## Prerequisites

- A CDQ API key. If you do not have one, contact your CDQ account manager.
- Postman installed (optional; any HTTP client that can send a `POST` request with a JSON body will work).


If you use Postman, you don't need to build the request manually:

1. Copy the curl example from Step 1 below.
2. Open Postman and paste the curl directly into the URL bar (or use **Import → Raw text**). Postman automatically parses the method, URL, headers, and body.
3. Replace `YOUR_API_KEY_HERE` with your actual API key in the `X-API-KEY` header field.


### Activating Data Sources

CDQ connects to a range of reference data sources, from business and tax registers to commercial data providers. These require a one-time activation for your organization before they can be used by any CDQ product, including company confirmation: navigate to **Global Settings**, find the data source, and activate it (some data sources need credentials or an API key of their own). Once activated, a data source is usable across all your workspaces.

Info
Data source activation happens once per organization, not per API key or per request. If company confirmation isn't finding a Business Partner you'd expect it to find, check whether the relevant data source is activated before assuming the input data is wrong.

## Step 1: Prepare and Send the Request

Provide the trading partner's data in the `businessPartner` object. Name, identifier, country, postal code, city, and street are required; house number is optional, and region is optional but only evaluated for Business Partners in the US, CA, AU, and BR.

Company confirmation and data quality confirmation are always returned; they're the two checks that determine the overall decision (see Step 2). Two additional checks are opt-in via `featuresOn`, since they add processing time and are only relevant to certain use cases:

| Feature  | Turn this on if... |
|  --- | --- |
| `ENABLE_QUALIFICATION_CONFIRMATION` | You need to confirm the trading partner's tax identifier is valid, e.g. before using it for invoicing or tax reporting. |
| `ENABLE_SANCTION_CONFIRMATION` | You need a compliance check against sanction/watchlists as part of onboarding, e.g. for AML or export-control requirements. |


Both are independent, so you can enable one, both, or neither. If your use case is a quick company/address sanity check, you can safely leave both off; the response will simply omit `qualificationConfirmation` and `sanctionComplianceConfirmation`.

Copy the curl below, replacing `YOUR_API_KEY_HERE` with your actual CDQ API key:


```bash
curl -i -X POST \
  https://api.cdq.com/data-clinic/rest/v2/businesspartners/confirm \
  -H 'Content-Type: application/json' \
  -H 'X-API-KEY: YOUR_API_KEY_HERE' \
  -d '{
    "businessPartner": {
      "names": [
        { "type": { "technicalKey": "LOCAL" }, "value": "CDQ AG" }
      ],
      "identifiers": [
        { "type": { "technicalKey": "CH_VAT_ID" }, "value": "CHE-218.608.886" },
        { "type": { "technicalKey": "CH_UID" }, "value": "CHE-218.608.886" }
      ],
      "addresses": [
        {
          "country": { "shortName": "CH" },
          "postCodes": [ { "value": "9008" } ],
          "localities": [ { "value": "St. Gallen" } ],
          "thoroughfares": [ { "value": "Lukasstraße", "number": "4" } ]
        }
      ]
    },
    "featuresOn": [
      "ENABLE_QUALIFICATION_CONFIRMATION",
      "ENABLE_SANCTION_CONFIRMATION"
    ]
  }'
```

Info
**Tips for preparing clean input.** A few small data-quality issues are easy to miss and can affect the result:

- Send identifiers exactly as they are registered. Strip suffixes your source system may add. For example, a Swiss VAT number formatted as `CHE-218.608.886 HR/MWST` should be sent as `CHE-218.608.886`, since the reference register may not recognize the `HR/MWST` suffix.
- For some countries, data quality confirmation expects more than one identifier type. For Switzerland, include both `CH_VAT_ID` and `CH_UID`. Without `CH_UID`, data quality confirmation can report an `ERROR`.
- Postal codes are compared exactly. Use the value as registered, not a variant your own system might store.


You can also send this request directly from the browser using the interactive console below. Add your API key, adjust the `businessPartner` body and `featuresOn` if needed, then send the request:

## Step 2: Send the Request and Review the Response

You should receive a `200 OK` response. Here is the complete, real response to the request above:


```json
{
    "status": {
        "code": 200,
        "technicalKey": "OK",
        "details": [
            {
                "id": 200702201,
                "message": "Data quality confirmation has OK decision.",
                "technicalKey": "DATA_QUALITY_CONFIRMATION_OK",
                "jsonRecord": { "explanation": "DATA_QUALITY_CONFIRMATION_OK", "key": "DATA_QUALITY_CONFIRMATION_OK" }
            },
            {
                "id": 200702110,
                "message": "Business Partner is found in Data Sources.",
                "technicalKey": "BUSINESS_PARTNER_FOUND_IN_DATA_SOURCES",
                "jsonRecord": { "explanation": "BUSINESS_PARTNER_FOUND_IN_DATA_SOURCES", "key": "BUSINESS_PARTNER_FOUND_IN_DATA_SOURCES" }
            },
            {
                "id": 200702120,
                "message": "Name meets expected requirements.",
                "technicalKey": "NAME_CONFIRMATION_OK",
                "jsonPath": "businessPartner.names[0].value",
                "jsonRecord": { "explanation": "NAME_CONFIRMATION_OK", "key": "name" }
            },
            {
                "id": 200702122,
                "message": "Identifiers meet expected requirements.",
                "technicalKey": "IDENTIFIER_CONFIRMATION_OK",
                "jsonPath": "businessPartner.identifiers[0].value",
                "jsonRecord": { "explanation": "VAT_NUMBER_CONFIRMATION_OK", "key": "vatNumber" }
            },
            {
                "id": 200702124,
                "message": "Country meets expected requirements.",
                "technicalKey": "COUNTRY_CONFIRMATION_OK",
                "jsonPath": "businessPartner.addresses[0].country.shortName",
                "jsonRecord": { "explanation": "COUNTRY_CONFIRMATION_OK", "key": "country" }
            },
            {
                "id": 200702132,
                "message": "Post Code meets expected requirements.",
                "technicalKey": "POST_CODE_CONFIRMATION_OK",
                "jsonPath": "businessPartner.addresses[0].postCodes[0].value",
                "jsonRecord": { "explanation": "POSTAL_CODE_CONFIRMATION_OK", "key": "postalCode" }
            },
            {
                "id": 200702128,
                "message": "Locality meets expected requirements.",
                "technicalKey": "LOCALITY_CONFIRMATION_OK",
                "jsonPath": "businessPartner.addresses[0].localities[0].value",
                "jsonRecord": { "explanation": "CITY_CONFIRMATION_OK", "key": "city" }
            },
            {
                "id": 200702130,
                "message": "Thoroughfare meets expected requirements.",
                "technicalKey": "THOROUGHFARE_CONFIRMATION_OK",
                "jsonPath": "businessPartner.addresses[0].thoroughfares[0].value",
                "jsonRecord": { "explanation": "STREET_CONFIRMATION_OK", "key": "street" }
            },
            {
                "id": 200702130,
                "message": "Thoroughfare meets expected requirements.",
                "technicalKey": "THOROUGHFARE_CONFIRMATION_OK",
                "jsonPath": "businessPartner.addresses[0].thoroughfares[0].number",
                "jsonRecord": { "explanation": "STREET_CONFIRMATION_OK", "key": "street" }
            },
            {
                "id": 200702101,
                "message": "Company confirmation has OK decision.",
                "technicalKey": "COMPANY_CONFIRMATION_OK",
                "jsonRecord": { "explanation": "COMPANY_CONFIRMATION_OK", "key": "COMPANY_CONFIRMATION_OK" }
            },
            {
                "id": 200702001,
                "message": "Overall confirmation has OK decision.",
                "technicalKey": "OVERALL_CONFIRMATION_OK",
                "jsonRecord": { "explanation": "OVERALL_CONFIRMATION_OK", "key": "OVERALL_CONFIRMATION_OK" }
            }
        ],
        "timestamp": "2026-07-30T11:35:57.390679619Z"
    },
    "dataQualityConfirmation": {
        "decision": { "technicalKey": "OK" },
        "summary": { "numErrors": 0, "numWarnings": 0, "numInfos": 2 },
        "details": {
            "infos": [
                {
                    "businessRule": { "name": "Identifier missing (D-U-N-S (World))", "ruleStatus": "RELEASED" },
                    "violationLevel": "INFO",
                    "violationMessage": "Business partner misses an optional D-U-N-S number."
                },
                {
                    "businessRule": { "name": "Mandatory administrative area missing (Switzerland)", "ruleStatus": "RELEASED" },
                    "violationLevel": "INFO",
                    "violationMessage": "The administrative area is missing for Switzerland"
                }
            ]
        }
    },
    "companyConfirmation": {
        "decision": { "technicalKey": "OK" },
        "summary": {
            "dataSource": { "name": "UID-Register", "technicalKey": "CH_UIDR" },
            "overallMatchingClassification": "FULL_MATCH",
            "overallMatchingScore": 0.999965949403138
        },
        "details": {
            "matchingProfile": {
                "matchingScores": {
                    "overall": { "classification": "FULL_MATCH", "value": 0.999965949403138 },
                    "businessPartner": { "classification": "FULL_MATCH", "value": 0.9995670058454211 },
                    "address": { "classification": "FULL_MATCH", "value": 0.927120469554908 }
                }
            },
            "matchedCompanyData": {
                "names": [
                    { "type": { "name": "Local Name", "technicalKey": "LOCAL" }, "value": "CDQ AG" },
                    { "type": { "name": "Legal Name", "technicalKey": "LEGAL" }, "value": "CDQ AG" }
                ],
                "legalForm": { "name": "Aktiengesellschaft", "technicalKey": "CH_0680", "mainAbbreviation": "AG", "categories": [ { "name": "Public Limited Company" } ] },
                "identifiers": [
                    { "type": { "name": "Federal Office of the Commercial Register ID", "technicalKey": "CH_EHRA_ID" }, "value": "1206654" },
                    { "type": { "name": "Federal Tax Administration ID", "technicalKey": "CH_ESTV_ID" }, "value": "052.0046.1654" },
                    { "type": { "name": "Organisation ID", "technicalKey": "CH_OID" }, "value": "CH32030769341" },
                    { "type": { "name": "Business identification number", "technicalKey": "CH_UID" }, "value": "CHE218608886" },
                    { "type": { "name": "VAT registration number", "technicalKey": "CH_VAT_ID" }, "value": "CHE218608886" },
                    { "type": { "name": "Legal Entity Identifier", "technicalKey": "LEI_ID" }, "value": "506700H559LEMQ0I8Y43" }
                ],
                "status": { "type": { "name": "Active", "technicalKey": "ACTIVE" } },
                "types": [ { "name": "Legal Entity", "technicalKey": "LEGAL_ENTITY" } ],
                "addresses": [
                    {
                        "country": { "shortName": "CH", "value": "Switzerland" },
                        "administrativeAreas": [ { "shortName": "SG", "type": { "technicalKey": "REGION" } } ],
                        "postCodes": [ { "value": "9008", "type": { "technicalKey": "REGULAR" } } ],
                        "localities": [ { "shortName": "St. Gallen", "value": "St. Gallen", "type": { "technicalKey": "CITY" } } ],
                        "thoroughfares": [ { "shortName": "Lukasstrasse", "number": "4", "value": "Lukasstrasse", "type": { "technicalKey": "STREET" } } ],
                        "types": [ { "name": "Legal Address", "technicalKey": "LEGAL" } ]
                    }
                ]
            }
        }
    },
    "qualificationConfirmation": {
        "decision": { "technicalKey": "FAIL" },
        "summary": {
            "decisionIdentifier": "UNKNOWN",
            "decisionName": "UNKNOWN",
            "decisionCity": "UNKNOWN",
            "decisionStreet": "UNKNOWN",
            "decisionPostalCode": "UNKNOWN"
        }
    },
    "sanctionComplianceConfirmation": {
        "decision": { "technicalKey": "OK" },
        "details": { "complianceListMatches": [] }
    }
}
```

The response has two layers: a shared `status.details` array at the top that lists every individual check performed across the whole request (including a status for each address and identifier field, keyed by `jsonPath`), and then one section per product (`dataQualityConfirmation`, `companyConfirmation`, `qualificationConfirmation`, `sanctionComplianceConfirmation`) with the detail behind that product's decision.

Info
Notice that `THOROUGHFARE_CONFIRMATION_OK` appears twice in `status.details`, once for `thoroughfares[0].value` (street name) and once for `thoroughfares[0].number` (house number). The house number gets its own independent pass/fail check, reusing the same `THOROUGHFARE_CONFIRMATION_OK`/`_FAIL` status rather than a new one. A mismatch fails on its own, even if the street name matches, while the check is skipped entirely if either side has no house number.

Warning
Notice that `qualificationConfirmation.decision.technicalKey` is `FAIL` while `status.details` still reports `OVERALL_CONFIRMATION_OK`. This confirms in practice what the endpoint's design states: qualification and sanction results do not affect the overall decision. The next section explains why this particular request resulted in `UNKNOWN` rather than `VALID` or `INVALID`.

### Interpreting the Overall Decision

Look for `OVERALL_CONFIRMATION_OK` or `OVERALL_CONFIRMATION_FAIL` in `status.details`:

| technicalKey  | Meaning |
|  --- | --- |
| `OVERALL_CONFIRMATION_OK` | The trading partner's data was successfully confirmed. |
| `OVERALL_CONFIRMATION_FAIL` | At least one required check did not pass. |


Warning
Only **company confirmation** and **data quality confirmation** currently influence the overall decision. Qualification and sanction compliance results are informational only, as shown in the example above.

### Company Confirmation and the Golden Record

`companyConfirmation` reports whether the submitted data matches a known company. Alongside the overall `matchingClassification` and `matchingScore`, `details.matchedCompanyData` returns a reference-enriched golden record, the trusted version of the Business Partner found in the reference data source (in the example above: legal form, identifiers, status, and type).

Each individual attribute used for matching also gets its own entry in `status.details`, identified by its `jsonPath`, for example `NAME_CONFIRMATION_OK` for `businessPartner.names[0].value`, or `THOROUGHFARE_CONFIRMATION_OK` for the street. A failed attribute would appear the same way, with a `_FAIL` suffix instead. Each attribute is compared using a method suited to how much variation is normal for that field:

| Attribute  | Comparison method |
|  --- | --- |
| Name | Legal form is extracted and compared first; a mismatch fails the name check outright. The remaining name is cleaned and standardized (case, special characters, transliteration) before an exact comparison. |
| Identifier | Compared exactly after cleaning. The identifier type must also match, except for countries with no dedicated reference data source (including `GB` and `US`), where only the identifier value is compared. |
| Postal code | Compared exactly after removing special characters and whitespace. |
| City | Similarity comparison (Q-gram); considered a match at 0.8 or higher. |
| Thoroughfare (street) | Similarity comparison (Q-gram); considered a match at 0.79 or higher. |
| Country | Compared exactly. |
| House number | Extracted from the thoroughfare value if not provided separately, then compared as an independent check; a mismatch fails on its own, even if the street name matches. Skipped (no decision) if either side has no house number at all. |
| Region | Compared exactly; only evaluated for Business Partners in the US, CA, AU, and BR. |


### Data Quality Confirmation

`dataQualityConfirmation.decision.technicalKey` gives the overall data quality outcome (`OK` or `FAIL`). The `summary` breaks it down into `numErrors`, `numWarnings`, and `numInfos`, and `details` lists each individual issue with the violated `businessRule`, its `violationLevel` (`INFO`, `WARNING`, or `ERROR`), and a human-readable `violationMessage`. In the example above, these are two `INFO`-level notes about optional data that happens to be missing.

Info
Errors and warnings here influence the overall decision. Some error types also affect a specific attribute's status directly. For example, an error of type `IDENTIFIER_FORMAT_INVALID` causes the identifier confirmation itself to fail, regardless of whether the identifier otherwise matches the golden record.

### Qualification and Sanction Confirmation (Optional)

`qualificationConfirmation` (included only when `ENABLE_QUALIFICATION_CONFIRMATION` is on) reports separate decisions for the identifier, name, city, street, and postal code in `summary` (`decisionIdentifier`, `decisionName`, `decisionCity`, `decisionStreet`, `decisionPostalCode`), based on a check against official tax databases. Each of these can independently be `VALID`, `INVALID`, or `UNKNOWN`.

Info
**Why the example above returns `UNKNOWN`, not `INVALID`.** Tax identifier validation relies on VIES (VAT Information Exchange System), an EU system that only covers EU member states and a small number of EEA countries. Switzerland is not part of VIES, so it cannot be queried at all, and the result is `UNKNOWN`, not a failed validation. For any Business Partner in a non-VIES country (e.g. `CH`, or `GB`), expect `UNKNOWN` regardless of how correct the tax identifier actually is. `UNKNOWN` means the check could not be performed; it does not mean the identifier is invalid. This is also why `qualificationConfirmation.decision.technicalKey` is `FAIL` in the example: the check failed to produce a result, not because the data was wrong. For Business Partners outside VIES coverage, rely on **company confirmation** instead, which in this example confirmed the same Business Partner successfully via the Swiss `CH_UIDR` register.

`sanctionComplianceConfirmation` (included only when `ENABLE_SANCTION_CONFIRMATION` is on) lists every sanction or watchlist match found in `details.complianceListMatches`. An empty array, as in the example above, means no match was found.

## Troubleshooting Common Issues

**400 Bad Request**
A mandatory field is missing or malformed. The response names the exact missing field via `jsonPath`, for example:


```json
{
  "status": {
    "code": 400,
    "technicalKey": "BAD_REQUEST",
    "details": [
      {
        "message": "Please provide businessPartner.names[0].value.",
        "technicalKey": "MANDATORY_FIELD",
        "jsonPath": "businessPartner.names[0].value",
        "jsonRecord": { "explanation": "No name provided as input.", "key": "name" }
      }
    ]
  }
}
```

**403 Forbidden**
Not `401 Unauthorized` as might be expected: a missing `X-API-KEY` header returns `403 Forbidden` with a different response shape than the endpoint's own error format:


```json
{
  "message": "Neither Authorization nor X-API-Key set from <your IP>",
  "status": 403,
  "error": "Authorization Failed",
  "path": "/data-clinic/rest/v2/businesspartners/confirm"
}
```

**`OVERALL_CONFIRMATION_FAIL` with no obvious attribute mismatch**
This can happen when no reference data source is available for the business partner's country. Check coverage before assuming the data itself is wrong.

**Low `overallMatchingScore` despite correct-looking data**
Check the per-attribute statuses individually; a single low-similarity field (e.g. a misspelled street) can lower the overall score even when the rest of the record matches well.

**`qualificationConfirmation` decisions are all `UNKNOWN`**
This means the check could not be performed, most commonly because the tax register behind it (VIES) doesn't cover the trading partner's country. See the explanation under Qualification and Sanction Confirmation above.

## Summary

In this tutorial, you learned what the Confirm Business Partner endpoint checks, how to send a confirmation request, and how to interpret the overall decision together with the company, data quality, qualification, and sanction results.

## Related Resources

- [Confirm Business Partner API](https://developer.cdq.com/apis/data-clinic-api/api-v2/business-partners/paths/~1v2~1businesspartners~1confirm/post)


## Your opinion matters!

We are constantly working on providing an outstanding user experience with our products. Please share your opinion about this tutorial!