UK B2B Lead Verifier: Companies House and Email avatar

UK B2B Lead Verifier: Companies House and Email

Pricing

from $2.70 / 1,000 row judgeds

Go to Apify Store
UK B2B Lead Verifier: Companies House and Email

UK B2B Lead Verifier: Companies House and Email

Verify UK B2B leads against Companies House: each lead is marked ok, dissolved, in distress or not on the register, with company number, address and register link, plus email, website and phone checks. Paste columns, a CSV URL or the dataset of a lead-finder run.

Pricing

from $2.70 / 1,000 row judgeds

Rating

0.0

(0)

Developer

Pradio Actors

Pradio Actors

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 hours ago

Last modified

Share

What does UK B2B Lead Verifier do?

UK B2B Lead Verifier checks every lead on a bought UK list against the Companies House register and returns one verdict row per lead. Companies House is the UK's public register of companies. A lead that claims a UK company is matched on its name, number or website stem; its email domain, website and phone are checked alongside. Each judged row carries 33 fields. You get the verdict, a match score and the register page to open as proof. You get the matched company's number, status, registered address, dates, SIC codes, filing deadlines and officer count. And you get flags for disposable, role and free-provider emails. Paste the list in as columns, point it at a CSV or JSON file, or pick the dataset of a lead-finder run, then press Start.

On a measured run of 100 leads, all 100 came back judged: 70 verified ok, 4 read dissolved, 2 in_distress and 1 not_on_register. The other 23 read unverifiable, because no register entry matched them confidently. The run named the closest entry and declined to guess. A judged row costs $0.005.

Who uses UK B2B Lead Verifier

WhoWhat they run it for
A founder or sales-ops lead who just paid for a listCheck every row before the first send instead of spot-checking a sample by hand.
An outbound team about to spend sender reputationSuppress dissolved and in-distress companies before the campaign, not after the bounces.
A buyer disputing a bad listThe dead rows come back with the reason and the register link, ready to take to the seller for a refund.
A calling team working a phone columnValid numbers come back with a line type; invalid ones are flagged before anyone dials.

Features

  • Register verdict on every UK-signalled lead. The claimed company name, company number or website stem is matched against Companies House. A UK signal is a company number, a +44 phone, a .uk domain or a UK legal form such as ltd or plc in the name. A row carrying no UK signal is never searched, so a non-UK company can never collect a false UK verdict.
  • No check behind a paywall. Register status, MX records on the email domain, a live-website probe, a phone-number parse with line type, and the email flags below. No paid lookups and no API keys.
  • Columns, a file or another run's dataset. Paste emails, urls, companies and phones as parallel columns, or set leadListUrl to a CSV or JSON list. Or pick a lead-finder run's dataset in datasetId and chain the two runs.
  • Email checks beyond MX. Every email is flagged as disposable (a throwaway-address domain), a role mailbox (info@, sales@, support@ and similar) or a free provider (gmail.com, outlook.com, btinternet.com and similar). No request is made: the address alone answers.
  • Register detail for every matched company. SIC codes, whether the accounts or the confirmation statement are overdue, and the number of active officers, all from Companies House.
  • Duplicates dropped before you pay. A lead that repeats an earlier lead's company number or email is dropped before judging, and RUN_SUMMARY says how many and on which key.
  • No login, no browser, no key. Every check is a plain logged-out GET or a DNS lookup. Per lead that is one MX lookup on the email domain, one read of the website and one register search. With register detail on, a matched company adds two more register reads: its data page and its officers page. The register's developer API needs a key; the public search this Actor reads does not.
  • A lead is matched only when the names agree. The register's name must be the lead's claim, legal form aside, or a former name the register lists for the company. A near miss, two same-named companies, or a name that sits inside a longer one reads unverifiable with the closest entry named in reason. A dissolved or in-distress verdict needs the closest agreement of all. It also needs a website or email domain that does not point to another company, so a live lead is never marked dead on a guess.
  • Polite register reads. Lookups run one at a time with a pause between them, under the register's 120-requests-a-minute guideline. A refusal is backed off once, not hammered.
  • Misses are free and named. A failed register read, a block, a timeout or a row with nothing to judge is pushed uncharged, with the reason on it.

What you can count on

  • You pay for each ROW the run judged, and for nothing else. An unverifiable row is one of those and is billed: its email, website and phone checks ran on it, even when the register gave no answer for it. Only a miss is free: a row the run could not judge is pushed as an uncharged ITEM_STATUS row, so you see the miss and are never billed for it.
  • Every row is charged only after it is written to your dataset; a row you cannot see is never billed.
  • A run that finds nothing returns one NOTHING_TO_JUDGE row that says so, never an empty dataset.
  • A spending limit stops the run cleanly with a STOPPED_EARLY row saying how many rows were returned and how many were not.
  • Every run writes a RUN_SUMMARY entry with rowsFetched, rowsPushed, rowsCharged and duplicatesDropped, so a short run and a broken one are told apart.
  • If the register changes what it answers, the run fails with the error in the log. It never returns rows full of nulls and calls it success.
  • No value is invented: a field the register does not show is null, and this page says which.

Why this one

  • The most-used alternative on this platform was run on 2026-09-25 with two of the company names from this Actor's example input. It is a lead finder, so it answers a different question: it returned 3 rows, and email, phone and domain were empty on all 3. This Actor's email and domain come from your own list, so they are not the win. What it adds is the register's word on each lead: in its example run it read Tesco PLC ok and Carillion PLC in_distress (in liquidation), each with the register page linked.
  • No start fee of ours. Start fees across the Store run from $0.00001 to $0.10 before the first row comes back. Apify's standard start charge applies ($0.00005 per event, one event per GB of run memory with a minimum of one, so one event per run at this Actor's 256 MB default), and this Actor declares no extra start event of its own.
  • A miss is free and explained. The row still lands in your dataset, uncharged, with the failure named on it.
  • The judged rate is measured, not promised. A list of 123 leads the product had never seen came back 123 of 123 judged. Judged is not verified: unverifiable is a judged, billed verdict, and it was 23 of the 100 leads in the scale run. The list was worked in runs under the 100-lead cap and read without a browser.
  • Every matched row carries evidence_url, the live register page behind the verdict. In the measured run it filled on all 76 matched rows of the 100.

What data does UK B2B Lead Verifier return?

One row per lead. A real dissolved verdict from a run, for a lead that gave its company number, looks like this:

{
"email": "info@maplin.co.uk",
"domain": "maplin.co.uk",
"status": "dissolved",
"match_score": 98,
"reason": "MAPLIN ELECTRONICS (HOLDINGS) LIMITED (04220419): dissolved on Companies House; the email domain accepts mail; the email is a shared role mailbox; the website answers",
"error": null,
"found": true,
"is_active": false,
"claimed_company": "04220419",
"matched_name": "MAPLIN ELECTRONICS (HOLDINGS) LIMITED",
"normalised_status": "dissolved",
"status_as_of": "2026-09-25T13:25:32.003Z",
"phone_number_status": null,
"phone_line_type": null,
"website_answers": true,
"email_domain_accepts_mail": true,
"dead_reason": "dissolved on the register 2019-12-07",
"evidence_url": "https://find-and-update.company-information.service.gov.uk/company/04220419",
"company_status": "dissolved",
"company_number": "04220419",
"company_type": "ltd",
"date_of_creation": "2001-05-21",
"date_of_cessation": "2019-12-07",
"address": {
"premises": "C/O Pricewaterhousecoopers Llp Central Square",
"address_line_1": "29 Wellington Street",
"locality": "Leeds",
"postal_code": "LS1 4DL"
},
"register_description": "04220419 - Dissolved on 7 December 2019",
"sic_codes": [
"74990"
],
"officer_count": 3,
"accounts_overdue": null,
"confirmation_statement_overdue": null,
"email_disposable": false,
"email_role_account": true,
"email_free_provider": false,
"row_type": "ROW"
}

The verdict vocabulary

status carries one of five charged verdicts, or a miss word on an uncharged row:

statusWhat it means
okMatched on the register and active there. The website, email and phone checks sit beside the verdict and do not change it, so an ok row can still carry website_answers false. On a weaker match (match_score under 90) the verdict is about the entity matched_name names, so check it is yours.
dissolvedMatched on the register; the entry shows it dissolved, by its status word or, when the entry carries no status word, by a closed company type such as converted-or-closed named on dead_reason.
in_distressMatched; the register shows liquidation, administration, receivership or similar.
not_on_registerThe UK register was searched and no entry matched the claim. It means "no UK company matched", not "the company does not exist".
unverifiableCharged. The register gave no verdict on the row, but the email, website and phone checks ran on it and their results are on the row, so it is billed like any other judged row. The register gives no verdict when the lead carried no UK signal to search on, when the register had already refused the run and was not asked for this row, when the matched entry carried no status the run could classify, or when no single register entry matched the claim closely enough to name it. On that last kind reason names the closest entry and why it was not taken. Its match_score is null. A row whose own register read was attempted and failed is a miss, not this verdict, and is free.
fetch_failed, blocked, timeout, aborted, not_found, errorMisses: the run could not judge this row. Pushed as uncharged ITEM_STATUS rows so you see them, never billed. These are the only free rows. The status word error means an unexpected failure; it is not the error field, which carries the failure's detail.

Two words are easy to confuse and worth a second look. not_on_register is a verdict: the register was searched and nothing matched. not_found is a miss: the row carried no email, website, company or phone to judge, and it is free.

Every field, in order

FieldWhat it carries
emailThe email the lead row claimed, echoed back so the verdict lines up with your list. Null when the list carried no email column.
domainThe domain the lead was judged on, taken from its website or else from its email address.
statusThe verdict, or the miss word on an uncharged row.
match_scoreRegister-match confidence: how strongly the register answer supports the verdict, 0 to 100. A score of 95 or more is the claim itself, name or number, and 90 is a former name the register lists for the company. A score of 85 means one name starts with the other and the longer adds one distinctive word, and only an ok verdict is given on such a match; matched_name and evidence_url name and link the entity it is about. A dissolved or in-distress verdict always scores 90 or more. A fixed middling value on not_on_register; null on unverifiable, where a number would claim confidence the register never gave.
reasonOne sentence naming the matched company and what each check found, readable without opening the register.
errorThe failure's detail in words, such as HTTP 403, on an uncharged miss row whose status is fetch_failed, blocked, timeout or error. Not the same thing as the status word error, which names the kind of miss. Null on not_found and aborted misses, whose reason says why, and on every judged row.
foundTrue when a register entry matched the claim.
is_activeTrue when the matched company is active on the register right now, that is only when normalised_status is active.
row_typeROW for a judged lead, ITEM_STATUS for an uncharged miss, NOTHING_TO_JUDGE or STOPPED_EARLY on a status row.
register_descriptionThe register's own one-line description of the company, verbatim: such as "Incorporated on 27 November 1947", truncations included.
addressThe registered office address the register publishes, as an object of region, locality, postal code and address lines. Null when the register's entry carries none, as on the Bank of England's royal-charter entry.
company_typeThe register's type word for the company, verbatim: ltd, plc, converted-or-closed and the like.
company_statusThe register's own status word: active, liquidation, dissolved and so on.
date_of_creationThe incorporation date the register shows.
company_numberThe register's permanent number for the matched company.
date_of_cessationThe dissolution date, when the register's entry names one. A dissolved row whose entry carries no date stays null.
claimed_companyThe company your lead row claimed, echoed from the input: a name or a UK company number.
matched_nameThe register's legal title for the entry it matched, so a trading name still lands on the right company.
normalised_statusThe normalised register read. active, dissolved and in_distress: the matched company's state on the register. no_match: the register was searched and no entry matched. unchecked: the register gave no usable answer for this row. That is when the row gave no company name, number or company domain to search on, when the register had refused the run and was not asked, when the matched entry's status could not be classified, when no single entry matched closely enough, or when the lead is on a UK public-sector domain. A row whose own register read failed also reads unchecked, but its status names the miss (blocked, timeout or fetch_failed) and it is free. not_applicable: the row carried no UK signal, so the register was not asked.
status_as_ofWhen the verdict was computed, ISO-8601.
phone_number_statusvalid or invalid as a number. Whether a line rings is not claimed.
phone_line_typeThe line type where the number parses: mobile, fixed_line, toll_free, voip and similar.
website_answersWhether the website answers HTTP at all. A 403 still counts as an answer; false means nothing answered.
email_domain_accepts_mailWhether the email's domain publishes MX records. The mailbox itself is never probed.
dead_reasonOn a dissolved or not_on_register verdict, which check killed the row, with the register date when there is one. An in_distress company (in liquidation or administration) is still on the register, not dissolved, and an unverifiable one was never confirmed, so they carry none.
evidence_urlThe register page to open to see the evidence behind the verdict.
sic_codesThe matched company's SIC codes, five-digit strings such as 47110: what the company says it does. An empty list when the register holds none.
officer_countHow many officer appointments are active, not resigned, from the count the register prints on the company's officers page. Only the number is read.
accounts_overdueTrue when the register's next accounts due date has passed. Null when the register shows no due date, as for a dissolved company.
confirmation_statement_overdueTrue when the register's next confirmation statement due date has passed. Null when the register shows none.
email_disposableTrue when the email is on a known disposable, throwaway address domain.
email_role_accountTrue when the email is a shared role mailbox such as info@, sales@ or support@, not a named person's.
email_free_providerTrue when the email is on a free mailbox provider such as gmail.com or outlook.com, not a company domain.

The four register-detail fields are null when no company matched, or when includeRegisterDetail is off. The three email flags are null when the row has no email.

Status rows carry four fields of their own: reason says why the run ended that way, and rowsFetched, rowsReturned and rowsRemaining give the counts.

On the measured run's 100 judged rows, the register fields filled on the rows the register matched. matched_name, company_number, company_type, company_status, register_description and evidence_url filled on 76 of 100: every ok, dissolved and in_distress row. address, date_of_creation, sic_codes and officer_count filled on 75, and the two overdue flags on 71. match_score filled on 77, every row but the 23 unverifiable ones. claimed_company, domain, status, reason, found, is_active, normalised_status and status_as_of filled on all 100. date_of_cessation filled on all 4 dissolved rows. dead_reason filled on 5: the 4 dissolved rows and the 1 not_on_register row.

One field stays null on every judged row by design, not by accident:

FieldWhy it stays null
errorIt fills only on an uncharged miss row, where it gives the failure's detail. A judged row has nothing to report.

The Console's Overview view hides error; the All fields view and every export carry it.

How much does it cost?

The price is $0.005 per judged row, billed as the row-judged event, and only after the row is written to your dataset. A dead lead is still a judged row: a dissolved or not_on_register verdict is the answer you paid for, and an unverifiable row is billed too, because its email, website and phone checks ran on it even when the register gave no answer. Only ITEM_STATUS miss rows, status rows and dropped duplicates are never billed.

Leads in the listIf every lead judges
100$0.50
1,000$5.00
10,000$50.00

Coverage was measured on a different list from the run above: a set of 123 leads the product had never seen came back 123 of 123 judged, worked in runs under the 100-lead cap, with no browser. A lead the run cannot read comes back as a free row, so you pay only for judged leads, unverifiable ones included. A run judges at most 100 leads, so longer lists are worked in runs of 100. Apify also bills its standard apify-actor-start charge at $0.00005 per start event, one event per GB of run memory with a minimum of one. At this Actor's 256 MB default that is one event per run. This Actor adds no start fee of its own.

How do I use UK B2B Lead Verifier?

  1. Open the Actor page and press Start.
  2. Feed it leads one of three ways. Paste the emails, urls, companies and phones columns, keeping the rows parallel so position 1 in each array is the same lead. Or set leadListUrl to a CSV or JSON list. Or pick a lead-finder run's dataset in datasetId.
  3. Leave maxItems at its default of 100, which is also the cap, or set a lower number of rows the run may return.
  4. Press Start. Verdict rows land in the dataset as they are judged.

Example input, the same four leads the input form ships with:

{
"emails": ["press.office@tesco.com", "info@carillion.co.uk", "info@maplin.co.uk", "j.smith@mailinator.com"],
"urls": ["https://www.tesco.com", "https://www.carillion.co.uk", "https://www.maplin.co.uk", "https://zzqx-nonexistent-example.com"],
"companies": ["TESCO PLC", "CARILLION PLC", "04220419", "ZZQX EXAMPLE NONEXISTENT LIMITED"],
"phones": ["+44 1992 632222", "+44 20 7946 0958", "", ""],
"maxItems": 100
}

The same run through the Apify API is one call:

curl -X POST "https://api.apify.com/v2/acts/Pradio~b2b-leads/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"emails": ["info@carillion.co.uk"], "companies": ["CARILLION PLC"]}'

Input

InputTypeDefaultWhat it does
emailsarrayfour example rowsThe email each lead row claims. Its domain is checked for MX records; the mailbox is never probed.
urlsarrayfour example rowsThe website each lead claims, fetched once to see whether it answers. Its domain also helps match the company on the register.
companiesarrayfour example rowsThe company name or UK company number each row claims. A registered name or a number matches sharpest.
phonesarrayfour example rowsThe phone number each row claims, checked for validity and line type.
leadListUrlstringnoneA CSV or JSON lead list read instead of, or as well as, the columns above.
maxItemsinteger100The most rows one run returns, capped at 100. Leads beyond the cap are not judged.
datasetIdstringnoneAn Apify dataset to read leads from, such as a lead-finder run's output: one of yours, or a public dataset ID.
datasetFieldMapobjectnoneWhich field of each dataset item holds the company, company number, email, phone and website, when the guesses miss.
includeRegisterDetailbooleantrueRead SIC codes, overdue filings and the officer count for each matched company. Off gives a faster run.

The columns are parallel

emails[i], urls[i], companies[i] and phones[i] describe one lead. Any subset works. A lead with only a domain is still matched by the domain's name stem. A lead with only a phone still gets its number checked. A row with nothing usable comes back as a not_found miss, free.

leadListUrl

Point it at a CSV file or a JSON array of objects; an Apify dataset-items URL from a lead-finder run works directly. CSV headers are matched by the names list sellers actually use. The email column answers to email, e-mail or mail. The website answers to website, url or domain. The company answers to company, organisation or business. The phone answers to phone, telephone or mobile. A company number column answers to company_number, crn or registration_number. Only those columns are read. A contact's name, a job title or any other column in the file is never copied into a row. A list URL that answers with an error fails the run instead of returning an empty dataset.

Chain a lead-finder run with datasetId

Pick the dataset of any earlier run in datasetId, or give its ID, and each item becomes a lead. The run reads the items through the Apify API with its own access, one page at a time, until it holds as many distinct leads as maxItems allows. From each item it reads five values and nothing else: the company name, the company number, the email, the phone and the website. A contact's name, a job title or any other field is never copied into a row.

{
"datasetId": "YOUR_LEAD_FINDER_DATASET_ID",
"maxItems": 100
}

The run guesses where each value sits. The company is companyName, company_name or company, then title or name, but those two only when the item carries no person fields such as firstName or jobTitle. The company number is companyNumber or company_number. The email is email or the first of emails. The phone is phone or the first of phones. The website is website, url or domain. When your dataset names them differently, say where they are in datasetFieldMap. A path can reach into an object or a list, and an empty string skips that value:

{
"datasetId": "YOUR_LEAD_FINDER_DATASET_ID",
"datasetFieldMap": {
"company": "organization.name",
"email": "contact.emails[0]",
"url": "organization.website",
"phone": ""
}
}

A dataset ID that does not exist, or that the run may not read, fails the run with the ID in the error. It never returns an empty dataset as if the list were empty.

Email checks

Every email is read three ways from the address alone, with no request and no mailbox probe. email_disposable is true on a throwaway-address domain, checked against the public disposable-email-domains list (CC0), bundled with the Actor and dated 24 September 2026. email_role_account is true on a shared mailbox such as info@, sales@, accounts@ or noreply@. email_free_provider is true on a free mailbox such as gmail.com, hotmail.co.uk, btinternet.com or gmx.de. They run on every lead with an email, whatever the other inputs:

{
"emails": ["info@acme-example.co.uk", "j.smith@gmail.com", "sales@mailinator.com"],
"maxItems": 3
}

Register detail

For every lead matched on the register, the run reads two more Companies House pages: the company's public data page and its officers page. They are read one at a time, with the same pause as the search. From them it fills sic_codes, accounts_overdue, confirmation_statement_overdue and officer_count. Only the officer count is kept; no officer's name, address or date of birth is read into a row. Turn it off for a faster run that returns the verdict and the company particulars only:

{
"companies": ["00445790", "03782379"],
"includeRegisterDetail": false
}

Duplicate leads

Before judging, a lead that repeats an earlier lead's company number or email is dropped. Company numbers are compared upper-cased and zero-padded to eight digits, so 445790 and 00445790 are the same company. Emails are compared trimmed and case-folded. Two leads with the same company name and different emails are both kept. RUN_SUMMARY carries the count under leads: inputDuplicatesDropped, and inputDuplicatesByKey with company_number and email. Dropped duplicates are never billed.

{
"emails": ["press.office@tesco.com", "Press.Office@tesco.com"],
"companies": ["TESCO PLC", "TESCO PLC"]
}

Worked examples

Use it to verify a UK lead list you pasted in before a campaign. Leads go in as parallel columns, the same shape as the input form's example:

{
"emails": ["press.office@tesco.com", "info@carillion.co.uk"],
"urls": ["https://www.tesco.com", "https://www.carillion.co.uk"],
"companies": ["TESCO PLC", "CARILLION PLC"],
"phones": ["+44 1992 632222", ""]
}

Use it to find the disposable, role and free-mail addresses in a lead list. Each email is flagged from the address alone, and its domain is checked for MX records:

{
"emails": ["info@carillion.co.uk", "j.smith@gmail.com", "sales@mailinator.com"],
"maxItems": 3
}

Use it to check whether UK companies are still trading. This returns verdicts and particulars only, without the extra register reads:

{
"companies": ["00445790", "03782379", "04220419"],
"includeRegisterDetail": false
}

The output of a lead-finder run works too. Pick its dataset and the run reads the leads straight from it:

{
"datasetId": "YOUR_LEAD_FINDER_DATASET_ID",
"maxItems": 100
}

A bought list you hold as a CSV file works the same way. Host the file anywhere that answers a plain GET:

{
"leadListUrl": "https://example.com/bought-leads.csv",
"maxItems": 100
}

Output

Every row carries a row_type. ROW and ITEM_STATUS are the kinds of row a run returns per lead; NOTHING_TO_JUDGE and STOPPED_EARLY are single rows that close a run which did not simply fill:

row_typeWhat it means
ROWA judged lead, unverifiable included. Charged.
ITEM_STATUSA miss the run could not judge. Pushed so you see it, never billed.
NOTHING_TO_JUDGEThe input gave the run no leads: empty columns and no leadListUrl, or a file whose rows carried none of the four columns. One row, uncharged. A zero result is an answer, not silence.
STOPPED_EARLYThe charge limit was reached before every fetched row was pushed. The row carries rowsFetched, rowsReturned and rowsRemaining, so finishing and being cut short never produce the same dataset.

Every run also writes a RUN_SUMMARY entry to the run's key-value store: rowsFetched, rowsPushed, rowsCharged, rowsUncharged, duplicatesDropped, startedAt and finishedAt. Under leads it carries the input's own counts: leadsRead, inputDuplicatesDropped, inputDuplicatesByKey and leadsJudged, plus datasetItemsRead when a dataset was read. It is the fast way to tell a short list from a broken run. When maxItems cuts a run short, rowsFetched against rowsPushed there shows what the list held against what came back.

What can you do with the data?

Take the dead rows back for a refund. Filter status to dissolved, in_distress and not_on_register, and dead_reason plus evidence_url itemise exactly which leads failed and on what evidence. On the measured 100-lead run that meant 4 dissolved rows, 2 in distress and 1 with no register match. That is the report a money-back guarantee asks for. Another 23 came back unverifiable, because no register entry matched them confidently. The run declines to guess, so a live company is never reported dead; give those leads a company number and run them again.

Clean a list before the first send. Suppress every row that is not ok, then read website_answers, email_domain_accepts_mail and phone_number_status on the survivors to drop any whose checks you would not send to. ok means the company is live on the register; the check fields are the deliverability read. 70 of the 100 measured leads verified active.

Re-verify an ageing list. Companies dissolve between the day a list is bought and the day it is worked; 4 of the 100 measured leads already had. Upload last quarter's extract again and status_as_of dates every verdict, so a stale row is caught before it is sent.

Triage a dialling list. phone_number_status drops numbers that do not parse. phone_line_type splits mobiles from fixed lines and VoIP, so the team dials the rows worth dialling first.

Use UK B2B Lead Verifier with AI agents

$claude mcp add --transport http apify "https://mcp.apify.com?tools=Pradio/b2b-leads"

Paste that line into your agent's setup and it can start runs and read verdict rows as tools.

Personal data

Attribution. The register evidence on every row is public sector information from Companies House. Contains public sector information licensed under the Open Government Licence v3.0, at https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/.

Transparency. Verdicts derive from the public Companies House register and from DNS and HTTP checks on the details each lead claims. The basis for processing is legitimate interests: checking that business data sold as accurate is accurate. A data subject may object and request deletion of their particulars. To do so, open an issue on the Actor's Issues tab asking for removal. Do not put the email address in the issue, which is public; name the company only, or nothing at all. The removal is then arranged privately from there.

What a row carries. A verdict row carries the verdict and the matched company particulars it needs: company name, number, status, registered office address, SIC codes, filing deadlines and a count of active officers. It does not echo officers' names, dates of birth or home addresses: the officers page is read for its count line only. PSC names are not read at all. Of the list you upload, or the dataset you pick, only the email, website, company, company number and phone values are read. A person's name or any other field never reaches a row.

How the register is read. Logged-out plain GETs, no credential and no bypass, one page per request, with maxItems capped at 100 rows a run. For a matched company the run also reads its public data page on data.companieshouse.gov.uk and its officers page, the same register. A refusal (403 or 429) is waited out once; a second one stops every register read for the rest of the run, and nothing retries past it. The remaining rows are still judged on their email checks, with normalised_status set to unchecked.

Controller. You choose which list to upload and why, so the controller for the personal data in it is you or your organisation. The register data is published for public use under the licence above.

Release notes

  • 2026-09-25: stricter company matching. A lead is matched to a register entry only when the names agree. The register's name must be the lead's claim, legal form aside, or a former name the register lists. So "british aerospace" is BAE SYSTEMS PLC, not the dissolved Society of British Aerospace Companies. Two same-named entries or a name inside a longer one now read unverifiable, never dissolved. So does a lead whose domain points to another company, with reason naming the closest entry, and a lead on a UK public-sector domain, ok included, with reason saying a public body is not a company on the register. A name followed by two or more extra words in the register's name (HM TREASURY UK SOVEREIGN SUKUK PLC for "hm treasury") scores under 80 and is not matched. A note in round or square brackets on your lead's name, such as "(2015-2022)" or "[old account]", is set aside when the name as written finds no match, so "abellio scotrail (2015-2022)" is ABELLIO SCOTRAIL LTD. A dissolved or in-distress verdict needs a match score of 90 or more.
  • 0.2: an Apify dataset as input (datasetId, with datasetFieldMap for other field names), so a lead-finder run can be verified in the next step. Email flags for disposable domains, role mailboxes and free providers. SIC codes, overdue accounts and confirmation statements, and the active officer count for each matched company (includeRegisterDetail, on by default). Duplicate leads by company number or email are dropped before judging and counted in RUN_SUMMARY.
  • 0.1: first public build, a lead-list verifier on the Companies House register. Per-lead verdicts (ok, dissolved, in_distress, not_on_register, unverifiable) with the matched company's particulars and evidence link, MX, website and phone checks on the row, and a 100-lead cap per run.

Limits

  • UK register only, and it only asks about UK-signalled leads. The register check is Companies House. A lead carrying a UK signal is searched. The signal is a company number, a +44 phone, a .uk domain or a UK legal form in the name. One that matches nothing reads not_on_register, which means "no UK company matched", not "the company does not exist". A lead with no UK signal is never asked and reads unverifiable with normalised_status not_applicable. A non-UK row can still match a same-named UK company, since overseas groups do register UK subsidiaries and branches. When the row's own domain or phone contradicts the UK claim, no company is named. The row reads unverifiable, and reason names the same-named entry and says it may be a different company. A lead on a UK public-sector domain (gov.uk itself, .gov.uk, .nhs.uk, .ac.uk, .police.uk and similar) takes no company's verdict by name, ok included. A government department, a council or a university is not a company on the register, so the row reads unverifiable and reason says so.
  • 100 leads a run. maxItems is capped at 100 and the run judges no more than that. A longer list is worked in runs of 100, each billed for its own judged rows.
  • The mailbox itself is never probed. email_domain_accepts_mail is an MX check on the domain, so a full or dead inbox still reads true.
  • "Valid" stops at the number. phone_number_status and phone_line_type come from parsing the number itself. Whether the line rings is not claimed, and no carrier lookup is made.
  • "Answers" is generous on purpose. website_answers is true when anything answers HTTP, even a 403 or a parked page. False means nothing answered at all.
  • Free-mailbox emails never drive a match. A lead whose only company hint is a gmail address is never guessed at the register from the word "gmail".
  • One refusal is backed off, not hammered. A 403 or 429 from the register pauses the run once. A second refusal marks the register down. The hit row is pushed free as blocked. Later rows are judged on the other checks with normalised_status set to unchecked.
  • Reads are sequential. Register calls run one at a time with a pause between them, under the register's 120-a-minute guideline, so a large list takes a while. Register detail adds two reads per matched company, so a 100-lead run takes about three times as long with it on. That is the polite speed, not a fault.
  • The disposable list is a dated copy. email_disposable checks the public list as bundled on 24 September 2026. A throwaway domain registered after that reads false until the copy is refreshed.
  • Errors run towards naming a miss, never towards a fake verdict. A check that fails says so on the row rather than guessing. A field the register does not publish is null rather than filled.

Troubleshooting

I uploaded 50 leads but only 47 rows came back. Where are the rest? Two places to look. Leads repeating an earlier lead's company number or email are dropped before judging and never billed, so repeats collapse to one row each. And maxItems caps how many rows are pushed. RUN_SUMMARY splits it exactly: leads.inputDuplicatesDropped with the key under leads.inputDuplicatesByKey, then rowsFetched, rowsPushed and duplicatesDropped.

The dataset has a single row and it is not a verdict. Is the run broken? No. That is a NOTHING_TO_JUDGE status row: the input gave it no leads. Check the columns are parallel arrays, or that leadListUrl answered and its headers were recognised.

A row says unverifiable with normalised_status not_applicable, but the company is real. The row carried no UK signal: no company number, +44 phone, .uk domain or UK legal form in the name. The UK register was not asked. The checks that did run (email domain, website, phone) are on the row. If the company is UK, give it a .uk website, a +44 number or its Companies House name and it will be searched.

A row says unverifiable with normalised_status unchecked, but the company is real. The register may not have been read for that row, usually because it refused an earlier request and the run stopped asking. Or the register answered with an entry whose status the run could not classify; company_status then carries the register's own word. The other checks still ran and are on the row. Re-run the list once the register is answering again. A third case: the register was searched and no single entry matched the claim closely enough, and reason names the closest entry and why. Give the lead its exact Companies House name or its company number and it will be matched.

The run ended with a STOPPED_EARLY row. Your charge limit was reached. The status row carries rowsReturned and rowsRemaining; raise the limit and re-run to see the rest. Rows already returned stay billed, and nothing after them is.

Something looks wrong? Report a problem through the Issues tab on the Actor's Store page and it gets looked at.

FAQ

Can I use integrations with UK B2B Lead Verifier? Yes. The dataset exports as JSON, CSV, Excel and more, so a dead-row report drops straight into a spreadsheet or a CRM import. Apify integrations such as Zapier and Make can start a run when a new list lands.

Can I use UK B2B Lead Verifier with the Apify API? Yes. POST the same JSON the input form takes to the Actor's run endpoint; the curl in the how-to section is the whole call. Runs, datasets and schedules are all reachable through the standard API and client libraries.

Can I use UK B2B Lead Verifier through an MCP server? Yes. The snippet in the AI-agents section registers this Actor with a compatible agent, which can then start runs and read the verdict rows.

Is it legal to check a lead list this way? The register half of each verdict is Companies House's public company search, read with a plain logged-out GET. That is public sector information licensed under the Open Government Licence v3.0, with no login and no bypass. The input side is a list you already hold. What you may do with it sits between you and its seller.

Not affiliated

UK B2B Lead Verifier is an independent tool. It is not affiliated with, endorsed by or connected to Companies House, Apify or any lead-list provider. Company data comes from the public register under the Open Government Licence v3.0.