# B2B Lead Verifier 🕵️ (registry, insolvency, sanctions) (`tagadanar/b2b-lead-verifier`) Actor

Check a B2B lead list against the official company registers of France, the UK and Germany: legal entity (SIREN, company number, HRB), still trading or in insolvency, a sanctions screen against OFAC/UN/EU/UK lists, and a confidence score that shows its workings. No API key. Platform usage included.

- **URL**: https://apify.com/tagadanar/b2b-lead-verifier.md
- **Developed by:** [Tagada Data](https://apify.com/tagadanar) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $14.00 / 1,000 lead verifieds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## B2B Lead Verifier: check your list against the official company registers

Paste a lead list, get back one row per lead saying whether the company really
exists, whether it is still trading, and how sure we are that we found the
right one. France, the United Kingdom and Germany. No API key needed.

Most lead lists rot. Companies close, get struck off, go into administration,
change their name after a sale, or never existed as a legal entity in the first
place. A scraped directory will not tell you: the listing stays up. The company
register will, and this actor asks it for you, one lead at a time.

### What you get for every lead

| Field | What it tells you |
| --- | --- |
| `verdict` | One sentence, readable in a spreadsheet cell: "Verified, active company", "In insolvency, do not extend credit", "Company is closed", "Not found in the company register" |
| `confidence` / `confidenceBand` | 0 to 100, and the band: verified, likely, uncertain, unverified |
| `confidenceReasons` | Every point that went into the score, in words. No black box |
| `legalName`, `registryId` | The registered legal entity: SIREN (France), company number (UK), HRB/HRA (Germany) |
| `companyStatus` | active, ceased, dissolved, in-insolvency |
| `matchScore`, `matchType` | How the name matched, and how closely |
| `matchAlternatives` | Other companies that nearly matched, when the register cannot tell them apart |
| `insolvencyStatus`, `insolvencyHits` | Collective procedures with their date, court and a link to the official notice |
| `sanctionsStatus`, `sanctionsHits` | Matches against OFAC SDN, UN, EU, UK OFSI and the US Consolidated Screening List |
| `legalForm`, `incorporationDate`, `registeredAddress`, `activityCode`, `officers` | The register's own record, so you can fix a stale CRM row |
| `riskFlags` | insolvency, closed, sanctions, address-mismatch |

### Where the data comes from

| Country | Register | Insolvency | Key needed |
| --- | --- | --- | --- |
| France | SIRENE and the RNE, through recherche-entreprises.api.gouv.fr | BODACC | no |
| United Kingdom | Companies House | The Gazette | no (optional, see below) |
| Germany | Handelsregister (Registerportal) | Insolvenzbekanntmachungen | no |
| Everywhere | — | — | OFAC, UN, EU, UK OFSI and US CSL sanctions lists, downloaded fresh on every run |

All of them are official government sources, and all of them are free. Nothing
here comes from a resold third-party database, so the data is as current as the
register itself.

### Three ways to give it your list

Paste it:

```json
{
  "leads": [
    { "companyName": "Decathlon France", "country": "FR", "city": "Villeneuve-d'Ascq" },
    { "companyName": "Marks and Spencer Group plc", "country": "GB" },
    { "companyName": "Zalando SE", "country": "DE", "city": "Berlin" }
  ]
}
```

Point it at another run's dataset (any lead scraper: Google Maps, Yellow Pages,
Europages, our own lead actors). Company name, town and country are picked up
from the usual field names automatically:

```json
{ "leadsDatasetId": "aBcDeF1234567890" }
```

Point it at a CSV export from your CRM. Comma and semicolon files both work,
and the header row names the columns:

```json
{ "leadsCsvUrl": "https://example.com/exports/prospects.csv", "defaultCountry": "FR" }
```

A registration number, when you have one, skips the matching entirely and is
always exact:

```json
{
  "leads": [
    { "registrationNumber": "552120222" },
    { "companyName": "Wilko", "registrationNumber": "09563205", "country": "GB" },
    { "companyName": "Zalando SE", "registrationNumber": "HRB 158855" }
  ]
}
```

### How the matching works, and where it can be wrong

Every lead name is normalised (accents folded, `&` spelled out, `P.L.C.`
collapsed to `plc`), then compared against every name the register holds for a
company: the legal name, the trading name and any shopfront name. BlaBlaCar is
registered as COMUTO, and that is the sort of thing this handles.

The ladder, best rung first: the registration number, the exact legal name, the
same words in a different order, the same name once the legal form is set aside
("Siemens AG" is "Siemens Aktiengesellschaft"), one name inside the other, and
finally a typo-tolerant fuzzy match. A town or a postcode that agrees with the
registered office adds points; one that clearly disagrees takes them away,
because "same name, other town" is the most common way to match the wrong
company on a national register.

Two things it does deliberately rather than guessing:

- **It says "ambiguous" when it is.** If two companies score within four points
  of each other, you get the best one, the runners-up, and a much lower
  confidence. Give the lead a town or a postcode and the ambiguity usually
  disappears.
- **It never invents a country.** A lead with no country and no clue in its
  domain, email or registration number is reported as "country unknown" and is
  not billed.

Known limits, stated plainly:

- Only France, the UK and Germany have registers here. Everything else comes
  back as "country not covered", free of charge.
- On the UK free path we read one page of results (20 companies). A very common
  name may need a postcode on the lead to be found reliably; the row says so
  when that happens.
- German insolvency notices are removed from the official portal six months
  after a proceeding ends, so a company that recovered years ago will read as
  clear. That is the register's rule, not ours.
- A UK insolvency notice is matched by name and then confirmed against the
  company number in the notice's own structured data, so a notice about a
  different company with the same name is dropped rather than pinned on your
  lead.

### Do I need a Companies House API key?

No. UK leads work out of the box through the free public company search on
GOV.UK.

If you already have a key (they are free from
developer.company-information.service.gov.uk), put it in
`companiesHouseApiKey` and UK leads get relevance-ranked search, SIC codes and
richer status data. The key stays yours, it is never stored, and we never
charge you for Companies House lookups. We do not ship a key of our own, on
purpose: a shared key would be rate-limited across every user of this actor.

### What you pay for

One charge per lead a register actually answered on, match or no match. A "no
match" is a real answer and the reason many people run this, so it is billed.

These are free:

- leads in a country we do not cover
- leads with no usable company name
- leads where a source was unreachable and we could not answer

Platform usage is included in the price. There is nothing else to pay.

### Use cases

**Lead-gen agencies.** Run a scraped list through this before you deliver it.
"Verified against the company register" is a line item you can charge for, and
a bounced list is a refund you avoid.

**Sales teams.** Kill the dead rows before the SDRs call them. Sort by
`confidence` descending and work down.

**Credit and finance.** `insolvencyStatus` and `insolvencyHits` come straight
from BODACC, The Gazette and Insolvenzbekanntmachungen, with the court and the
notice link, before you extend terms.

**Compliance and onboarding.** Registry identity plus a sanctions screen in one
run, with the source and the list date on every row.

**CRM hygiene.** `legalName`, `registeredAddress` and `incorporationDate` are
the register's own values. Use them to correct records that were typed in by
hand three years ago.

### FAQ

**How do I verify a French company by SIREN?** Put the nine-digit number in
`registrationNumber`. SIRET (fourteen digits) and an FR VAT number both work
too, and all three skip name matching entirely.

**Can I check if a UK company is in liquidation?** Yes. `companyStatus` carries
the Companies House status, and `insolvencyHits` carries the actual Gazette
notices, each with its type ("Administrators appointed", "Winding-up
petition"), its date and a link.

**Can I check if a German company is insolvent?** Yes, against
Insolvenzbekanntmachungen, the official portal run by the state justice
administrations. Note that the Handelsregister entry of an insolvent company
often still reads "aktuell", so the register alone is not enough. Wirecard AG
is the standard example, and this actor flags it correctly.

**Is a BODACC "procédure de conciliation" the same as insolvency?** No, and we
do not treat it as one. Conciliation is a confidential preventive negotiation
that healthy companies use. It appears in `insolvencyHits` with
`severity: "preventive"` and does not zero your lead's score. Only collective
procedures (redressement, liquidation, sauvegarde) do.

**What happens if a source is down?** The row says so:
`insolvencyStatus: "source-error"` or a `sanctionsListsUnavailable` list, and
that lead is not billed. The run finishes; it does not fail.

**How many leads can one run handle?** Ten thousand. French leads run at about
two per second; German ones are slower, about four seconds each, because the
Handelsregister is a session-based portal that has to be queried politely.

**Is this GDPR-friendly?** The sources are official public registers, published
by governments for exactly this purpose. Directors' names appear where the
register publishes them.

**Can I run it on a schedule?** Yes. Point it at a dataset ID or a CSV URL and
schedule it weekly to keep a list from going stale.

### Related actors

- **French Company KYC** for the full French record: officers, finances, BODACC history.
- **German Company KYC** for the Handelsregister XJustiz extract.
- **Companies House Monitor**, **BODACC Insolvency Monitor**, **UK Insolvency
  Monitor** and **German Insolvency Monitor** to watch a portfolio for changes
  instead of checking it once.
- **Sanctions & Watchlist Screener** for names on their own, people included.

***

Keywords: b2b lead verification, lead list cleaning, company verification,
KYB, company register lookup, SIREN lookup, SIRET lookup, Companies House
lookup, Handelsregister lookup, HRB number, insolvency check, BODACC, The
Gazette, Insolvenzbekanntmachungen, sanctions screening, OFAC, lead enrichment,
CRM data cleaning, prospect verification.

# Actor input Schema

## `leads` (type: `array`):

Your lead list. Each entry can be a plain company name, or an object with any of <code>companyName</code>, <code>country</code>, <code>city</code>, <code>postalCode</code>, <code>registrationNumber</code> (SIREN/SIRET, UK company number or HRB), <code>domain</code>, <code>email</code>, <code>address</code>, <code>contactName</code>. A town or a postcode makes the match far more reliable when several companies share a name. Output from our lead scrapers can be pasted in as-is.

## `leadsDatasetId` (type: `string`):

Verify the output of another run instead of pasting it. Paste the dataset ID of any lead scraper run (Google Maps, Europages, Yellow Pages, our own lead actors). Company name, town and country are picked up automatically from the usual field names.

## `leadsCsvUrl` (type: `string`):

A public, direct link to a CSV export from your CRM. The header row names the columns; comma and semicolon files both work. Columns such as <code>company</code>, <code>country</code>, <code>city</code>, <code>zip</code>, <code>website</code> are recognised automatically.

## `defaultCountry` (type: `string`):

Used only for leads with no country of their own and no clue in their domain, email or registration number. Leave empty to report those leads as "country unknown" rather than guess.

## `minMatchScore` (type: `integer`):

How close a registered legal name has to be to your lead name before we call it a match, from 70 (loose) to 100 (the exact legal name only). 82 keeps "Decathlon France" matching "DECATHLON FRANCE SAS" while rejecting look-alikes in another town.

## `checkInsolvency` (type: `boolean`):

Look every matched company up in BODACC (France), The Gazette (UK) and Insolvenzbekanntmachungen (Germany) to see whether it is in a collective procedure, liquidation or administration. Adds about one second per lead.

## `screenSanctions` (type: `boolean`):

Screen every company and its directors against the OFAC SDN, UN, EU, UK OFSI and US Consolidated Screening lists, downloaded fresh from the official sources on every run. Adds about fifteen seconds once per run, then nothing per lead.

## `companiesHouseApiKey` (type: `string`):

UK leads work without this: we fall back to the free public company search on GOV.UK. Supplying your own key (free from <a href='https://developer.company-information.service.gov.uk/' target='_blank'>developer.company-information.service.gov.uk</a>) adds SIC codes and richer status data. The key is yours, is never stored, and we never charge you for Companies House lookups.

## `maxLeads` (type: `integer`):

Stop after this many leads. Use it to cap what a run can cost.

## Actor input object example

```json
{
  "leads": [
    {
      "companyName": "Decathlon France",
      "country": "FR",
      "city": "Villeneuve-d'Ascq"
    },
    {
      "companyName": "Marks and Spencer plc",
      "country": "GB"
    },
    {
      "companyName": "Zalando SE",
      "country": "DE",
      "city": "Berlin"
    }
  ],
  "defaultCountry": "",
  "minMatchScore": 82,
  "checkInsolvency": true,
  "screenSanctions": true,
  "maxLeads": 1000
}
```

# Actor output Schema

## `leads` (type: `string`):

One row per lead: registry match, alive-or-dead flag, sanctions screen and a confidence score.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "leads": [
        {
            "companyName": "Decathlon France",
            "country": "FR",
            "city": "Villeneuve-d'Ascq"
        },
        {
            "companyName": "Marks and Spencer plc",
            "country": "GB"
        },
        {
            "companyName": "Zalando SE",
            "country": "DE",
            "city": "Berlin"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tagadanar/b2b-lead-verifier").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "leads": [
        {
            "companyName": "Decathlon France",
            "country": "FR",
            "city": "Villeneuve-d'Ascq",
        },
        {
            "companyName": "Marks and Spencer plc",
            "country": "GB",
        },
        {
            "companyName": "Zalando SE",
            "country": "DE",
            "city": "Berlin",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tagadanar/b2b-lead-verifier").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "leads": [
    {
      "companyName": "Decathlon France",
      "country": "FR",
      "city": "Villeneuve-d'\''Ascq"
    },
    {
      "companyName": "Marks and Spencer plc",
      "country": "GB"
    },
    {
      "companyName": "Zalando SE",
      "country": "DE",
      "city": "Berlin"
    }
  ]
}' |
apify call tagadanar/b2b-lead-verifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tagadanar/b2b-lead-verifier"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ACluGnIAlEC8g6de8/builds/x9AUSADdceZUlEbrc/openapi.json
