# Run a compliance check on a company

Source: https://help.businessradar.com/api/guides/run-a-compliance-check
Updated: 2026-09-17

A compliance check screens a company — and optionally its directors and
ultimate beneficial owners — against sanctions lists, PEP data, enforcement
actions and adverse media. It runs in the background: you post it, wait for it,
then read the findings.

## Before you start

- An API key and a working first call — see
  [Authenticate and make your first request](/api/guides/authenticate-and-make-your-first-request).
- The company you want to screen, identified by name and country, a DUNS
  number, or a local registration number.

## Step 1: Find the company

Compliance checks reference a company by its Business Radar `external_id`. If
the company is already tracked, search for it.

**curl**

```bash
curl -sS -G https://api.businessradar.com/ext/v3/companies \
  -H "Authorization: Bearer $BUSINESSRADAR_API_KEY" \
  --data-urlencode "query=Acme Industries" \
  --data-urlencode "country=NL"
```

**python**

```python
page = client.companies.list(query="Acme Industries", country=["NL"])
for company in page.results:
    print(company.external_id, company.name, company.duns_number)
```

**typescript**

```ts
const page = await client.companies.list({ query: 'Acme Industries', country: ['NL'] });
for (const company of page.results) {
  console.log(company.external_id, company.name, company.duns_number);
}
```

**php**

```php
<?php

$page = $client->companies->list(query: 'Acme Industries', country: ['NL']);
foreach ($page->getItems() as $company) {
    echo $company->external_id, ' ', $company->name, PHP_EOL;
}
```

If you have identifying details rather than a search term, `GET /ext/v3/companies/match/`
resolves them to the single best match — internally first, then against Dun &
Bradstreet. A company that exists only at D&B comes back with `external_id:
null` and a `duns_number` you can register with.

**curl**

```bash
curl -sS -G https://api.businessradar.com/ext/v3/companies/match/ \
  -H "Authorization: Bearer $BUSINESSRADAR_API_KEY" \
  --data-urlencode "name=Acme Industries B.V." \
  --data-urlencode "country=NL" \
  --data-urlencode "address_locality=Amsterdam"
```

**python**

```python
# businessradar >= 1.25.0
match = client.companies.match(
    name="Acme Industries B.V.",
    country="NL",
    address_locality="Amsterdam",
)
print(match.external_id, match.duns_number, match.name)
```

**typescript**

```ts
// Not in @businessradar/businessradar 0.8.0 yet — plain fetch does the job.
const response = await fetch(
  'https://api.businessradar.com/ext/v3/companies/match/?' +
    new URLSearchParams({
      name: 'Acme Industries B.V.',
      country: 'NL',
      address_locality: 'Amsterdam',
    }),
  { headers: { Authorization: `Bearer ${process.env['BUSINESSRADAR_API_KEY']}` } },
);
const match = await response.json();
```

At least one of `name`, `duns_number`, `registration_number` or
`customer_reference` is required, and `country` must accompany a `name` or
`registration_number` lookup. The endpoint returns `404` when nothing matches.

## Step 2: Register the company if it is new

`POST /ext/v3/companies` registers a company and returns a **registration**, not
a company: the work happens in the background. Posting the same company again
returns the existing registration rather than creating a second one.

**curl**

```bash
curl -sS -X POST https://api.businessradar.com/ext/v3/companies \
  -H "Authorization: Bearer $BUSINESSRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "duns_number": "123456789",
    "customer_reference": "erp-4711",
    "submit_investigation_when_not_identified": true
  }'
```

**python**

```python
registration = client.companies.create(
    duns_number="123456789",
    customer_reference="erp-4711",
    submit_investigation_when_not_identified=True,
)
print(registration.external_id, registration.status)
```

**typescript**

```ts
const registration = await client.companies.create({
  duns_number: '123456789',
  customer_reference: 'erp-4711',
  submit_investigation_when_not_identified: true,
});
console.log(registration.external_id, registration.status);
```

**php**

```php
<?php

$registration = $client->companies->create(
    dunsNumber: '123456789',
    customerReference: 'erp-4711',
    submitInvestigationWhenNotIdentified: true,
);
echo $registration->external_id, ' ', $registration->status, PHP_EOL;
```

Poll `GET /ext/v3/registrations/{registration_id}` until `status` is
`registered`; the response then carries the `company` object with the
`external_id` you need. Registration moves through a long list of intermediate
states (`searching`, `registering`, `searching_directors`, …) and can end in
`company_not_found`, `invalid_input` or `failed`.

```json
{
  "external_id": "0e3c2b6a-58f3-4c21-9a4a-9d5f2a1c0b77",
  "status": "registered",
  "status_text": "Registered",
  "progress": 1.0,
  "finished_at": "2026-09-17T09:12:44Z",
  "duns_number": "123456789",
  "customer_reference": "erp-4711",
  "company": {
    "external_id": "a7b1f2c4-1e3d-4f5a-8b9c-0d1e2f3a4b5c",
    "duns_number": "123456789",
    "name": "Acme Industries B.V.",
    "country": "NL"
  }
}
```

With `submit_investigation_when_not_identified: true`, a company we cannot
identify becomes a missing-company investigation instead of a failure — track
it through `GET /ext/v3/companies/investigations`.

## Step 3: Start the check

`POST /ext/v3/compliance` takes either a `company_id` or a list of `entities`.
With a `company_id` you can also screen the people around the company: UBOs
above an ownership threshold and registered directors.

**curl**

```bash
curl -sS -X POST https://api.businessradar.com/ext/v3/compliance \
  -H "Authorization: Bearer $BUSINESSRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "a7b1f2c4-1e3d-4f5a-8b9c-0d1e2f3a4b5c",
    "name": "Acme onboarding 2026-Q3",
    "ubo_screening_enabled": true,
    "directors_screening_enabled": true,
    "ownership_screening_threshold": 25
  }'
```

**python**

```python
check = client.compliance.create(
    company_id="a7b1f2c4-1e3d-4f5a-8b9c-0d1e2f3a4b5c",
    name="Acme onboarding 2026-Q3",
    ubo_screening_enabled=True,
    directors_screening_enabled=True,
    ownership_screening_threshold=25,
)
print(check.external_id)
```

**typescript**

```ts
const check = await client.compliance.create({
  company_id: 'a7b1f2c4-1e3d-4f5a-8b9c-0d1e2f3a4b5c',
  name: 'Acme onboarding 2026-Q3',
  ubo_screening_enabled: true,
  directors_screening_enabled: true,
  ownership_screening_threshold: 25,
});
console.log(check.external_id);
```

**php**

```php
<?php

$check = $client->compliance->create(
    companyID: 'a7b1f2c4-1e3d-4f5a-8b9c-0d1e2f3a4b5c',
    name: 'Acme onboarding 2026-Q3',
    uboScreeningEnabled: true,
    directorsScreeningEnabled: true,
    ownershipScreeningThreshold: 25,
);
echo $check->external_id, PHP_EOL;
```

To screen people or organisations that are not a company in our data, leave
`company_id` out and pass `entities` instead — each entity takes a `name`, an
`entity_type`, and optionally `country`, `date_of_birth` (full or partial:
`1974`, `1974-03` or `1974-03-11`) and `aliases`.

The response is deliberately small: the `external_id` of the check.

```json
{ "external_id": "3f9a1c77-2b44-4e6d-8f0a-5c7d9e1b2a33" }
```

## Step 4: Wait for it

Two ways to find out that a check has finished. Poll while you are prototyping;
subscribe a webhook once you are in production.

### Poll the check

`GET /ext/v3/compliance/{external_id}` returns `status` — one of `pending`,
`queued`, `in_progress`, `searching_directors`, `completed` or `failed` — plus a
`progress` fraction and the high-level scores.

**curl**

```bash
CHECK_ID=3f9a1c77-2b44-4e6d-8f0a-5c7d9e1b2a33

curl -sS "https://api.businessradar.com/ext/v3/compliance/$CHECK_ID" \
  -H "Authorization: Bearer $BUSINESSRADAR_API_KEY"
```

**python**

```python

while True:
    status = client.compliance.retrieve(check.external_id)
    if status.status in ("completed", "failed"):
        break
    print(f"{status.progress:.0%}")
    time.sleep(10)
```

**typescript**

```ts
let status = await client.compliance.retrieve(check.external_id);
while (status.status !== 'completed' && status.status !== 'failed') {
  await new Promise((resolve) => setTimeout(resolve, 10_000));
  status = await client.compliance.retrieve(check.external_id);
}
```

**php**

```php
<?php

do {
    $status = $client->compliance->retrieve($check->external_id);
    sleep(10);
} while (!in_array($status->status, ['completed', 'failed'], true));
```

### Or subscribe to the event

Register a webhook once and Business Radar posts to it as the check moves.
`compliance_check.status_completed` fires when the check reaches `completed`;
`compliance_check.results.new` fires when monitoring later turns up something
new.

**curl**

```bash
curl -sS -X POST https://api.businessradar.com/ext/v3/webhooks/ \
  -H "Authorization: Bearer $BUSINESSRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/businessradar",
    "enabled": true,
    "subscriptions": [
      { "event_type": "compliance_check.status_completed" },
      { "event_type": "compliance_check.results.new" }
    ]
  }'
```

**python**

```python
webhook = client.webhooks.create(
    url="https://example.com/hooks/businessradar",
    enabled=True,
    subscriptions=[
        {"event_type": "compliance_check.status_completed"},
        {"event_type": "compliance_check.results.new"},
    ],
)
```

**typescript**

```ts
const webhook = await client.webhooks.create({
  url: 'https://example.com/hooks/businessradar',
  enabled: true,
  subscriptions: [
    { event_type: 'compliance_check.status_completed' },
    { event_type: 'compliance_check.results.new' },
  ],
});
```

**php**

```php
<?php

$webhook = $client->webhooks->create(
    subscriptions: [
        ['eventType' => 'compliance_check.status_completed'],
        ['eventType' => 'compliance_check.results.new'],
    ],
    url: 'https://example.com/hooks/businessradar',
    enabled: true,
);
```

Deliveries arrive as an envelope with the event name and the payload under a
named field:

```json
{
  "event_type": "compliance_check.status_completed",
  "compliance_check": {
    "external_id": "3f9a1c77-2b44-4e6d-8f0a-5c7d9e1b2a33",
    "name": "Acme onboarding 2026-Q3",
    "status": "completed",
    "created_at": "2026-09-17T09:15:02Z",
    "finished_at": "2026-09-17T09:18:41Z",
    "company": {
      "external_id": "a7b1f2c4-1e3d-4f5a-8b9c-0d1e2f3a4b5c",
      "name": "Acme Industries B.V.",
      "country": "NL"
    },
    "compliance_score": "medium",
    "sanction_score": "low",
    "pep_score": "medium",
    "adverse_media_score": "medium",
    "unreviewed_results_count": 7,
    "reviewed_results_count": 0
  }
}
```

Verify every delivery before trusting it: each carries an `X-Signature-SHA256:
sha256=<hex>` header, an HMAC-SHA256 of the raw body keyed with the webhook
secret shown once at creation. Non-2xx responses are retried up to three times
with exponential back-off, then marked `failed`.

## Step 5: Read the hits

`GET /ext/v3/compliance/{external_id}/results` lists the findings, newest first
by default. Filter by `result_type` (`sanction`, `pep`, `adverse_media`,
`enforcement`, `govt_owned`), by `entity`, or by `min_confidence`, and keep
`exclude_automated_false_positives` on to drop matches our models already rated
as false positives.

**curl**

```bash
CHECK_ID=3f9a1c77-2b44-4e6d-8f0a-5c7d9e1b2a33

curl -sS -G "https://api.businessradar.com/ext/v3/compliance/$CHECK_ID/results" \
  -H "Authorization: Bearer $BUSINESSRADAR_API_KEY" \
  --data-urlencode "result_type=sanction" \
  --data-urlencode "min_confidence=0.8" \
  --data-urlencode "exclude_automated_false_positives=true" \
  --data-urlencode "sorting=confidence" \
  --data-urlencode "order=desc"
```

**python**

```python
for result in client.compliance.list_results(
    check.external_id,
    result_type="sanction",
    min_confidence=0.8,
    exclude_automated_false_positives=True,
    sorting="confidence",
    order="desc",
):
    print(result.name, result.confidence, result.source_name)
```

**typescript**

```ts
for await (const result of client.compliance.listResults(check.external_id, {
  result_type: 'sanction',
  min_confidence: 0.8,
  exclude_automated_false_positives: true,
  sorting: 'confidence',
  order: 'desc',
})) {
  console.log(result.name, result.confidence, result.source_name);
}
```

**php**

```php
<?php

$results = $client->compliance->listResults(
    $check->external_id,
    resultType: 'sanction',
    minConfidence: 0.8,
    excludeAutomatedFalsePositives: true,
    sorting: 'confidence',
    order: 'desc',
);
foreach ($results->pagingEachItem() as $result) {
    echo $result->name, ' ', $result->confidence, PHP_EOL;
}
```

### What you get

```json
{
  "total_results": 3,
  "next_key": "eyJvZmZzZXQiOjIwfQ",
  "results": [
    {
      "external_id": "5d2f7c91-4b6e-4c1f-9a2b-7e8d3f0a1b23",
      "entity": {
        "external_id": "c1d2e3f4-5a6b-47c8-9d0e-1f2a3b4c5d6e",
        "name": "Jan de Vries"
      },
      "result_type": "sanction",
      "confidence": 0.93,
      "name": "Jan de Vries",
      "title": "Consolidated list of persons subject to EU financial sanctions",
      "text": "Listed under regulation 269/2014, entry added 2024-06-11.",
      "source_name": "EU Consolidated Sanctions List",
      "source_date": "2024-06-11",
      "url": "https://example.org/eu-sanctions/entry/4711",
      "addresses": [{ "country": "NL", "city": "Amsterdam" }],
      "tags": [{ "tag": "asset-freeze" }],
      "sources": [
        {
          "title": "Council Implementing Regulation (EU) 2024/1234",
          "url": "https://example.org/eur-lex/2024-1234",
          "domain": "example.org",
          "publication_date": "2024-06-11"
        }
      ],
      "automated_false_positive_rating": "no",
      "created_at": "2026-09-17T09:18:39Z"
    }
  ]
}
```

While a check is still running, `exclude_automated_false_positives=true`
returns only results our models have already validated — expect the list to
grow until `status` is `completed`.

## The whole thing

One onboarding run end to end: register the company, wait for it, screen it,
wait for that, and print the sanction hits worth a human's time.

**curl**

```bash
#!/usr/bin/env bash
set -euo pipefail

: "${BUSINESSRADAR_API_KEY:?export your API key first}"
BASE=https://api.businessradar.com/ext/v3
AUTH="Authorization: Bearer $BUSINESSRADAR_API_KEY"

registration=$(curl -fsS -X POST "$BASE/companies" \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{
    "duns_number": "123456789",
    "customer_reference": "erp-4711",
    "submit_investigation_when_not_identified": true
  }' | jq -r '.external_id')

while :; do
  body=$(curl -fsS "$BASE/registrations/$registration" -H "$AUTH")
  status=$(echo "$body" | jq -r '.status')
  [ "$status" = "registered" ] && break
  case "$status" in
    company_not_found|invalid_input|failed)
      echo "registration ended as $status" >&2; exit 1 ;;
  esac
  sleep 10
done

company=$(echo "$body" | jq -r '.company.external_id')

check=$(curl -fsS -X POST "$BASE/compliance" \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d "{
    \"company_id\": \"$company\",
    \"name\": \"Acme onboarding 2026-Q3\",
    \"ubo_screening_enabled\": true,
    \"directors_screening_enabled\": true,
    \"ownership_screening_threshold\": 25
  }" | jq -r '.external_id')

while :; do
  status=$(curl -fsS "$BASE/compliance/$check" -H "$AUTH" | jq -r '.status')
  [ "$status" = "completed" ] || [ "$status" = "failed" ] && break
  sleep 10
done

curl -fsS -G "$BASE/compliance/$check/results" -H "$AUTH" \
  --data-urlencode "result_type=sanction" \
  --data-urlencode "min_confidence=0.8" \
  --data-urlencode "exclude_automated_false_positives=true" \
  | jq -r '.results[] | "\(.confidence)\t\(.name)\t\(.source_name)"'
```

**python**

```python

from businessradar import BusinessRadar

client = BusinessRadar(api_key=os.environ["BUSINESSRADAR_API_KEY"])

FAILED_REGISTRATIONS = {"company_not_found", "invalid_input", "failed"}

registration = client.companies.create(
    duns_number="123456789",
    customer_reference="erp-4711",
    submit_investigation_when_not_identified=True,
)

while True:
    registration = client.companies.retrieve_registration(registration.external_id)
    if registration.status == "registered":
        break
    if registration.status in FAILED_REGISTRATIONS:
        sys.exit(f"registration ended as {registration.status}")
    time.sleep(10)

check = client.compliance.create(
    company_id=registration.company.external_id,
    name="Acme onboarding 2026-Q3",
    ubo_screening_enabled=True,
    directors_screening_enabled=True,
    ownership_screening_threshold=25,
)

while True:
    status = client.compliance.retrieve(check.external_id)
    if status.status in ("completed", "failed"):
        break
    time.sleep(10)

if status.status == "failed":
    sys.exit("the check failed — retry it or contact support")

for result in client.compliance.list_results(
    check.external_id,
    result_type="sanction",
    min_confidence=0.8,
    exclude_automated_false_positives=True,
):
    print(result.confidence, result.name, result.source_name)
```

**typescript**

```ts

const client = new BusinessRadar({ apiKey: process.env['BUSINESSRADAR_API_KEY'] });

const failedRegistrations = ['company_not_found', 'invalid_input', 'failed'];
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

let registration = await client.companies.create({
  duns_number: '123456789',
  customer_reference: 'erp-4711',
  submit_investigation_when_not_identified: true,
});

while (registration.status !== 'registered') {
  if (failedRegistrations.includes(registration.status)) {
    throw new Error(`registration ended as ${registration.status}`);
  }
  await sleep(10_000);
  registration = await client.companies.retrieveRegistration(registration.external_id);
}

const check = await client.compliance.create({
  company_id: registration.company.external_id,
  name: 'Acme onboarding 2026-Q3',
  ubo_screening_enabled: true,
  directors_screening_enabled: true,
  ownership_screening_threshold: 25,
});

let status = await client.compliance.retrieve(check.external_id);
while (status.status !== 'completed' && status.status !== 'failed') {
  await sleep(10_000);
  status = await client.compliance.retrieve(check.external_id);
}

if (status.status === 'failed') {
  throw new Error('the check failed — retry it or contact support');
}

for await (const result of client.compliance.listResults(check.external_id, {
  result_type: 'sanction',
  min_confidence: 0.8,
  exclude_automated_false_positives: true,
})) {
  console.log(result.confidence, result.name, result.source_name);
}
```

**php**

```php
<?php

require 'vendor/autoload.php';

use Businessradar\Client;

$client = new Client(apiKey: getenv('BUSINESSRADAR_API_KEY'));

$failedRegistrations = ['company_not_found', 'invalid_input', 'failed'];

$registration = $client->companies->create(
    dunsNumber: '123456789',
    customerReference: 'erp-4711',
    submitInvestigationWhenNotIdentified: true,
);

while ($registration->status !== 'registered') {
    if (in_array($registration->status, $failedRegistrations, true)) {
        exit("registration ended as {$registration->status}" . PHP_EOL);
    }
    sleep(10);
    $registration = $client->companies->retrieveRegistration(
        $registration->external_id,
    );
}

$check = $client->compliance->create(
    companyID: $registration->company->external_id,
    name: 'Acme onboarding 2026-Q3',
    uboScreeningEnabled: true,
    directorsScreeningEnabled: true,
    ownershipScreeningThreshold: 25,
);

do {
    sleep(10);
    $status = $client->compliance->retrieve($check->external_id);
} while (!in_array($status->status, ['completed', 'failed'], true));

if ($status->status === 'failed') {
    exit('the check failed — retry it or contact support' . PHP_EOL);
}

$results = $client->compliance->listResults(
    $check->external_id,
    excludeAutomatedFalsePositives: true,
    minConfidence: 0.8,
    resultType: 'sanction',
);
foreach ($results->pagingEachItem() as $result) {
    echo $result->confidence, ' ', $result->name, ' ', $result->source_name, PHP_EOL;
}
```

## Next steps

- [Register a portfolio and receive the right news](/api/guides/monitor-a-portfolio-for-news)
  to keep watching a company after onboarding.
- Reference: [Compliance](/api#tag/compliance), [Companies](/api#tag/companies),
  [Webhooks](/api#tag/webhooks).
