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
- 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
POSTrequest with a JSON body will work).
If you use Postman, you don't need to build the request manually:
- Copy the curl example from Step 1 below.
- 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.
- Replace
YOUR_API_KEY_HEREwith your actual API key in theX-API-KEYheader field.
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.
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.
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:
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"
]
}'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/MWSTshould be sent asCHE-218.608.886, since the reference register may not recognize theHR/MWSTsuffix. - For some countries, data quality confirmation expects more than one identifier type. For Switzerland, include both
CH_VAT_IDandCH_UID. WithoutCH_UID, data quality confirmation can report anERROR. - 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:
You should receive a 200 OK response. Here is the complete, real response to the request above:
{
"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.
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.
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.
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. |
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.
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. |
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.
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.
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.
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.
400 Bad Request A mandatory field is missing or malformed. The response names the exact missing field via jsonPath, for example:
{
"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:
{
"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.
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.
We are constantly working on providing an outstanding user experience with our products. Please share your opinion about this tutorial!