# UK Company KYB Check — Companies House Officers, PSC, Charges (`registrylens/uk-company-kyb`) Actor

Verify UK companies in bulk from official Companies House data: profile, officers, beneficial owners (PSC), charges, filing history, insolvency and risk flags with a KYB score. Pay per company.

- **URL**: https://apify.com/registrylens/uk-company-kyb.md
- **Developed by:** [Registry Lens](https://apify.com/registrylens) (community)
- **Categories:** Business, Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 company checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

### Verify UK companies in bulk and get a decision, not just rows

**UK Company KYB Check** turns a list of UK company numbers or names into **one scored KYB record per company**, built only from the official [Companies House](https://find-and-update.company-information.service.gov.uk/) Public Data API. Every record combines the profile, registered office, **officers**, **persons with significant control (beneficial owners)**, **charges**, filing history and **insolvency** data, then adds **risk flags** and an explainable **KYB score (0–100)**. Other listings return raw rows; this one returns the answer a compliance or onboarding team actually needs: *is this company real, active, and who is behind it?*

No browser, no stale cache: each run reads the live register. Run it from the Console, on a schedule, via the API, or as a tool from an AI agent.

### Sample output

```json
{
    "company_number": "00445790",
    "company_name": "TESCO PLC",
    "company_status": "active",
    "company_type": "plc",
    "date_of_creation": "1947-11-27",
    "sic_codes": ["47110"],
    "registered_office": { "address_line_1": "Tesco House", "locality": "Welwyn Garden City", "postal_code": "AL7 1GA", "country": "England" },
    "accounts": { "next_due": "2026-11-30", "overdue": false, "last_made_up_to": "2026-02-28", "last_type": "group" },
    "confirmation_statement": { "next_due": "2026-06-14", "overdue": false },
    "officers": { "active_count": 13, "resigned_count": 63, "items": [{ "name": "MURPHY, Kenneth", "role": "director", "appointed_on": "2020-10-01", "nationality": "Irish", "occupation": "Chief Executive" }] },
    "psc": { "count": 0, "has_statements": true, "statements": ["psc-exists-but-not-identified"], "items": [] },
    "charges": { "total_count": 4, "outstanding_count": 0, "satisfied_count": 4 },
    "insolvency": { "has_insolvency_history": false, "cases": [] },
    "risk_flags": ["psc_statement_only"],
    "kyb_score": 95,
    "source_urls": { "profile": "https://find-and-update.company-information.service.gov.uk/company/00445790" },
    "attribution": "Contains public sector information licensed under the Open Government Licence v3.0 (Companies House)."
}
```

Download the dataset as JSON, CSV, Excel or HTML, or read it through the API. Lookups that fail come back as items with `status` set to `not_found`, `unresolved` or `error` plus a plain-language `error`, and they are **never charged**.

### How much does it cost to check a UK company?

Pay per event, no subscription:

| Event | Price | When |
| --- | --- | --- |
| `company-check` | $0.008 per company | One successfully processed company, all selected sections included |
| `name-search` | $0.002 per name | One company name resolved to a company number |

That is $8 per 1,000 companies for a record that takes up to eight Companies House calls to assemble. Not-found companies, unresolved names and errors are free. Set a **maximum total charge** per run in the run options to cap spending; free-plan users can try it within their monthly credits.

### How to use it

1. Open the **Input** tab and paste company numbers (one per line) or company names.
2. Pick the sections you need. Profile and registered office are always included.
3. Click **Start**. With no input the Actor checks two example companies so you can see the output shape immediately.
4. Read the **Output** tab, export the dataset, or schedule the run to re-check your list weekly and alert on new `risk_flags`.

### Input

| Field | Meaning |
| --- | --- |
| `companyNumbers` | Companies House numbers, e.g. `00445790` or `SC123456`; digit-only values are zero-padded. Up to 1,000 per run |
| `companyNames` | Names resolved through Companies House search; only matches above `minMatchScore` are used, the rest are reported as `unresolved` and not charged |
| `minMatchScore` | Similarity threshold 0–1 (default 0.8); legal-form suffixes such as LTD or PLC are ignored |
| `sections` | Any of `officers`, `psc`, `charges`, `filingHistory`, `insolvency` |
| `maxItemsPerSection` | Cap per list section (default 50, max 500) |
| `includeResignedOfficers` | Also return resigned officers with their resignation dates |
| `maxUnresolved` | Stop after this many free failures (default 50), which stops a stale list from burning through the request budget |
| `apiKey` | Your own free Companies House key. Optional up to 500 companies per run, required above that; gives the run a dedicated rate limit |

```json
{
    "companyNumbers": ["00445790", "00041424"],
    "companyNames": ["Ocado Group"],
    "sections": ["officers", "psc", "charges", "insolvency"]
}
```

### Risk flags and the KYB score

The score starts at 100 and subtracts a fixed weight per flag, so every score can be explained to an auditor:

| Flag | Weight | Flag | Weight |
| --- | --- | --- | --- |
| `not_active` | 60 | `no_active_officers` | 20 |
| `insolvency_history` | 40 | `no_psc_declared` | 10 |
| `proposal_to_strike_off` | 30 | `recently_incorporated` (< 6 months) | 10 |
| `overdue_accounts` | 20 | `psc_statement_only` | 5 |
| `overdue_confirmation_statement` | 15 | `super_secure_psc` | 5 |
| `registered_office_in_dispute` | 20 | `outstanding_charges` | 5 |
| `undeliverable_registered_office` | 20 | `many_previous_names` (≥ 3) | 5 |
| `dormant_accounts` | 5 | `overseas_entity` | 0 (informational) |

The score is a screening aid, not a credit rating or legal advice.

### Data fields

| Field | Description |
| --- | --- |
| `company_status`, `company_status_detail` | Register status (`active`, `dissolved`, `liquidation`, `administration`, …) and details such as `active-proposal-to-strike-off` |
| `company_type`, `jurisdiction`, `sic_codes` | Legal form, jurisdiction, SIC activity codes |
| `registered_office`, `registered_office_is_in_dispute`, `undeliverable_registered_office_address` | Address and Companies House address warnings |
| `accounts`, `confirmation_statement` | Next due dates, overdue flags, last made-up dates, last accounts type |
| `previous_names` | Former names with effective and ceased dates |
| `officers` | Active and resigned counts and officer records (role, dates, nationality, residence, occupation, month/year of birth, officer id) |
| `psc` | Persons with significant control: kind, natures of control, notification dates, corporate identification; PSC statements when no PSC is identified |
| `charges` | Total, outstanding and satisfied counts plus charge records |
| `filing_history` | Latest filings (date, category, type, description) |
| `insolvency` | Insolvency history flag and cases with dates and practitioner count |
| `match` | For name lookups: the query and the similarity score of the chosen match |

The run summary in the key-value store record `OUTPUT` reports processed, charged, not found, unresolved and error counts, errors by category (rate limit, network, upstream shape, other) and the number of Companies House requests made.

### Tips

- Prefer **company numbers** over names: exact, cheaper, and no search step.
- Above roughly 70 companies per 5 minutes, add **your own Companies House API key** to get a dedicated rate limit.
- Reduce `sections` when you only need the profile and PSC data; runs finish faster.
- **AI agents:** this Actor is available as a tool through the Apify MCP server. Ask: "Check UK company 00445790 with UK Company KYB Check and summarise the risk flags." The agent passes the input JSON above and receives the dataset items.

### FAQ, limits and legal

- **Where does the data come from?** Exclusively from the Companies House Public Data API. The data is public sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/); every item carries the attribution string.
- **Is it real-time?** Yes. Each run queries the live register; nothing is cached between runs.
- **Rate limits?** Companies House allows 600 requests per 5 minutes per key. A full check uses up to 8 requests per company. The Actor rate-limits itself, retries transparently, and stops with a clear message if a run would reach the per-run request budget.
- **Personal data:** officer and PSC records contain names and partial dates of birth as published by Companies House. Use them in line with UK GDPR and your lawful basis.
- **Something wrong or missing?** Open an issue in the **Issues** tab. Custom fields, monitoring workflows and other registries are available on request.

# Actor input Schema

## `companyNumbers` (type: `array`):

Companies House company numbers, one per line (8 characters, e.g. 00445790 or SC123456). Digits-only values are zero-padded automatically.

## `companyNames` (type: `array`):

Company names to resolve to company numbers via Companies House search. The best match above the minimum match score is checked; others are reported as unresolved and not charged.

## `minMatchScore` (type: `number`):

Similarity (0–1) a search hit must reach to count as the company you meant. Legal-form suffixes such as LTD or PLC are ignored when comparing.

## `sections` (type: `array`):

Company profile and registered office are always included. Select which additional sections to fetch for every company.

## `maxItemsPerSection` (type: `integer`):

Cap for officers, PSCs, charges and filings returned per company. Higher values cost more API requests but not more credits.

## `includeResignedOfficers` (type: `boolean`):

Also return officers who have resigned (with their resignation date).

## `maxUnresolved` (type: `integer`):

Stop the run once this many inputs came back not found or unresolved. Failures are free for you but cost Companies House requests; the cap stops a stale list from burning through the request budget.

## `apiKey` (type: `string`):

Free at https://developer.company-information.service.gov.uk/. Optional up to 500 companies per run; required above that. With your own key the run gets the full dedicated rate limit (600 requests per 5 minutes).

## Actor input object example

```json
{
  "companyNumbers": [
    "00445790",
    "00041424"
  ],
  "companyNames": [],
  "minMatchScore": 0.8,
  "sections": [
    "officers",
    "psc",
    "charges",
    "filingHistory",
    "insolvency"
  ],
  "maxItemsPerSection": 50,
  "includeResignedOfficers": false,
  "maxUnresolved": 50
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "companyNumbers": [
        "00445790",
        "00041424"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("registrylens/uk-company-kyb").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 = { "companyNumbers": [
        "00445790",
        "00041424",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("registrylens/uk-company-kyb").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 '{
  "companyNumbers": [
    "00445790",
    "00041424"
  ]
}' |
apify call registrylens/uk-company-kyb --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,registrylens/uk-company-kyb"
        }
    }
}
```

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/yjI1fVheTosO6aQR6/builds/vFKGkBgnXLPOKeZBP/openapi.json
