Run a compliance check on a company
Resolve a company, start a screening, wait for it by polling or webhook, and read the sanctions, PEP and adverse-media hits it found.
Last updated
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.
- 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.
Search tracked companies
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"page = client.companies.list(query="Acme Industries", country=["NL"])
for company in page.results:
print(company.external_id, company.name, company.duns_number)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
$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.
Match on identifying details
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"# 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)// 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.
Register a company
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
}'registration = client.companies.create(
duns_number="123456789",
customer_reference="erp-4711",
submit_investigation_when_not_identified=True,
)
print(registration.external_id, registration.status)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
$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.
{
"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.
Start a compliance check
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
}'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)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
$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.
{ "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.
Poll until completed
CHECK_ID=3f9a1c77-2b44-4e6d-8f0a-5c7d9e1b2a33
curl -sS "https://api.businessradar.com/ext/v3/compliance/$CHECK_ID" \
-H "Authorization: Bearer $BUSINESSRADAR_API_KEY"import time
while True:
status = client.compliance.retrieve(check.external_id)
if status.status in ("completed", "failed"):
break
print(f"{status.progress:.0%}")
time.sleep(10)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
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.
Subscribe to compliance events
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" }
]
}'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"},
],
)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
$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:
{
"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.
List sanction hits above 80% confidence
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"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)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
$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
{
"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.
Complete onboarding run
#!/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)"'import os
import sys
import time
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)import BusinessRadar from '@businessradar/businessradar';
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
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 to keep watching a company after onboarding.
- Reference: Compliance, Companies, Webhooks.