# SiteVerdict — VAT & Company Number Validator (UK, EU) (`siteverdict/siteverdict-vat-validator`) Actor

Bulk-check EU, UK and Northern Ireland VAT numbers, UK company numbers and LEIs. Free local checksum first, then official VIES, HMRC, Companies House and GLEIF lookups with name match, consultation numbers and a timestamped audit trail.

- **URL**: https://apify.com/siteverdict/siteverdict-vat-validator.md
- **Developed by:** [Aman Thakran](https://apify.com/siteverdict) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SiteVerdict — VAT & Company Number Validator (UK, EU)

**Check thousands of EU, UK and Northern Ireland VAT numbers, UK company numbers and LEIs in one run.** Every number is checked locally for format and check digits first. Impossible numbers are flagged without a paid lookup. Plausible numbers then go to the public registry services: EU VIES, HMRC, Companies House and GLEIF. This Actor is independent and is not affiliated with or endorsed by any of them. Each result comes back with the registered name and address, a fuzzy match score against the name you supplied, a consultation number where the registry issues one, and a timestamped audit trail.

### Who it is for

- **Finance and AP teams** checking supplier VAT numbers before paying invoices or zero-rating intra-EU supplies.
- **E-commerce and marketplace operators** verifying B2B customers' VAT IDs at checkout or onboarding.
- **Compliance and KYB teams** who need a dated proof of every check.
- **Data teams** cleaning CRM or ERP master data: normalising formats, removing duplicates and flagging dead numbers.

### What you get per number

| Field | Meaning |
|---|---|
| `input`, `reference` | Exactly what you supplied, plus your own reference (invoice or PO number). |
| `number_type` | `vat`, `uk_company` or `lei`. These are auto-detected, or you can set them yourself. |
| `normalised_number`, `country` | A clean ID such as `DE136695976`. GR is mapped to EL, separators and case are fixed, and short Belgian or Greek numbers are padded. |
| `format_valid`, `checksum_valid` | The local check result. `checksum_valid: null` means the format has no check digit. |
| `registry_status` | `valid`, `invalid`, `unavailable` (registry down, retry later), `error`, or `not_checked` (local check only). |
| `active` | Whether the VAT registration is valid now, the company is active, or the LEI is ACTIVE and ISSUED. |
| `registered_name`, `registered_address` | As returned by the registry. Some countries, such as Germany and Spain, never return them. |
| `name_match_score` (0-100), `name_match` | A fuzzy match of your name against the registered name, ignoring Ltd, GmbH, S.A., accents and so on. Values are `exact`, `strong`, `partial`, `weak`, `mismatch` or `name_not_returned`. |
| `vies_trader_name_match` | VIES's own approximate-match verdict, where the member state supports it. |
| `consultation_number` | The VIES request identifier or HMRC consultation number. These are only issued when you give your own VAT number (see below). |
| `source`, `source_url`, `checked_at`, `registry_timestamp` | Where and when the result came from. |
| `evidence`, `evidence_key` | The request URL, HTTP status, time received and SHA-256 of the raw response. The raw response is saved in the run's key-value store under `evidence_key`. |
| `company_status`, `company_type`, `lei`, `lei_status` | Companies House and GLEIF details. |
| `charged_event` | What this row cost: `vat-checked`, `format-checked` or nothing. |

Sample row (abridged; real VIES answer for the example number, recorded 11 Oct 2026):

```json
{ "input": "IE6388047V | Google Ireland Limited | INV-1001", "reference": "INV-1001",
  "number_type": "vat", "normalised_number": "IE6388047V", "country": "IE",
  "format_valid": true, "checksum_valid": true, "registry_status": "valid", "active": true,
  "registered_name": "GOOGLE IRELAND LIMITED",
  "registered_address": "3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4",
  "name_match_score": 100, "name_match": "exact", "source": "VIES", "charged_event": "vat-checked" }
```

The dataset has four views: **Overview**, **Audit trail**, **Invalid & needs attention** and **UK companies & LEIs**. The `OUTPUT` record holds the run summary: counts, registry calls, retries and any disabled sources.

### How to use it

1. Paste your numbers into **Numbers**, one per line. You can add a name and your own reference after `|`.
2. Optional: add your own HMRC credentials (GB VAT numbers) and Companies House key (UK company numbers). Without them those numbers get a local format check only.
3. Set **Max cost per run** in the run options. The Actor stops cleanly when it is reached.
4. Click **Start**, then open the **Output** tab or download the dataset (CSV, JSON or Excel).

**The example input** (the same input the console pre-fills):

```json
{
  "numbers": [
    "IE6388047V | Google Ireland Limited | INV-1001",
    "DE143454214",
    "GB980780684",
    "03977902 | Google UK Limited"
  ]
}
```

These are public registry entries used only as examples. Without HMRC or Companies House keys, the two Irish and German numbers go to VIES (`vat-checked`, $0.004 each) and the two UK numbers get a local check (`format-checked`, $0.0005 each). The most it can cost is **$0.009**. If a member state is down, that row is `unavailable` and free. On 15 Oct 2026 this input took about 2 minutes, because the Actor waited for an unavailable member state to come back.

### Input examples

**Simple list.** Put one number per line. You can add a name and a reference after `|`:

```
IE6388047V | Google Ireland Limited | INV-1001
DE 143 454 214
FR40303265045 | Example SA | PO-77
GB980780684 | Acme Ltd
SC123456
5493001KJTIIGC8Y1R12
```

**Get consultation numbers for your audit file.** Set `viesRequesterVat` to your own EU or XI VAT number, and `hmrcRequesterVrn` to your UK VRN (this needs HMRC credentials).

**Clean a big list cheaply.** Set `checkMode: "format_only"`. Nothing is sent to any registry, and you only pay the small `format-checked` price per row.

### Sources and how each one is used

| Source | Used for | Access |
|---|---|---|
| **EU VIES** REST API (`/check-vat-number`, `/check-status`) | VAT numbers for all 27 EU member states and **XI** (Northern Ireland). | Open, no key. |
| **HMRC "Check a UK VAT number" API v2.0** | **GB** VAT numbers. Version 1 was switched off on 17 Feb 2025, and version 2 needs authentication. | **Your own** HMRC Developer Hub application (OAuth client credentials, scope `read:vat`). |
| **Companies House** Public Data API (`/company/{number}`) | UK company numbers. | **Your own** free API key (optional). |
| **GLEIF** LEI API | LEIs, plus optional LEI lookup for UK companies. | Open (CC0 data). |

How the Actor treats each registry:

- **Member-state outages:** VIES depends on each national database, and these go offline regularly. The Actor reads VIES's `/check-status` first and does not call a member state that is down. It then retries those numbers at the end of the run: 2 rounds, 60 s apart, by default (`unavailableRetryRounds`, up to 5; set it to 0 for the fastest run). Anything still down is returned as `unavailable` and **never charged**.
- **XI fallback:** if VIES XI is down and you have HMRC credentials, the Actor checks the UK VRN at HMRC instead and adds a note to the row.
- **VIES politeness:** the Actor runs at most 2 requests per second by default, and only one request at a time per member state. `MS_MAX_CONCURRENT_REQ` answers are backed off and retried.
- **Rate limits:** HMRC is kept at 2.5 requests per second (HMRC's default application limit is 3). Companies House is kept below 600 requests per 5 minutes. GLEIF is kept below 60 per minute.

#### Getting HMRC credentials (GB numbers)

1. Register at the [HMRC Developer Hub](https://developer.service.hmrc.gov.uk/) and create an application.
2. Subscribe it to **Check a UK VAT number (v2.0)**. Test in the sandbox, then request production access. HMRC says this takes about 2 weeks.
3. Paste the client ID and secret into the Actor. They are secret inputs (stored encrypted by Apify), sent only to HMRC's token endpoint, and masked in logs, error messages and output.

Without credentials, GB numbers still get the full local format and check-digit validation (`registry_status: not_checked`).

### Pricing (pay per event)

| Event | Price | When it is charged |
|---|---|---|
| `vat-checked` | $0.004 ($4 per 1,000) | A registry gave a definitive answer (valid or invalid) on a fresh call. |
| `format-checked` | $0.0005 ($0.50 per 1,000) | A local-only result: an invalid format or check digit, format-only mode, no credentials for that registry, or a duplicate already checked in this run. |
| nothing | $0 | The registry was `unavailable` or returned an `error`. |

Examples: 1,000 EU numbers checked at VIES cost about **$4.00**. A 10,000-row format-only clean-up costs **$5.00**. You pay only these event prices; Apify platform usage for the run is included.

The Actor checks your **Max cost per run** before every registry call and stops cleanly when the limit is reached.

### FAQ

**Is a valid checksum the same as a valid VAT number?**
No. A valid checksum only means the number *could* exist. Only the registry can confirm that it is registered.

**Why is there no name for German or Spanish numbers?**
Those member states do not publish names through VIES. Supply the name and VIES may still answer `vies_trader_name_match: VALID/INVALID`.

**What about UK VAT numbers after Brexit?**
GB numbers are not in VIES any more. They are checked with HMRC. XI numbers (Northern Ireland, goods) are in VIES.

**Do duplicates cost extra?**
No. Identical number and name pairs are merged into one row (`duplicate_inputs`). The same number with a different name reuses the cached registry answer and costs only `format-checked`.

**Can I resume a run that was aborted?**
Yes. Delivered rows are remembered for the run and are not repeated or charged twice.

### Limits

- VIES and HMRC show the registry's **current** state only. They give no history.
- The local check-digit rules follow the published national algorithms, cross-checked against an independent open-source implementation (stdnum) on more than 90,000 generated numbers (automated test, last passed 17 Oct 2026). Some special cases can be stricter or looser than the national authority. When in doubt, the registry decides.
- UK company numbers have no check digit, so only the format can be checked locally.
- EU OSS ("EU…") and non-EU VAT numbers (Norway, Switzerland and so on) are not supported.
- HMRC credentials take HMRC about 2 weeks to issue.

### Your data, storage and retention

- Results go only to **your own Apify account**: the run's dataset, the `OUTPUT` record and, when `storeEvidence` is on (the default), one raw registry response per row in the run's key-value store. Raw responses can include a sole trader's name and address. Set `storeEvidence: false` to keep none.
- These run storages are kept for your Apify plan's data-retention period, unless you delete them sooner. The Actor keeps no state between runs.
- The Actor contacts only the registries listed above. It sends nothing to the developer, and the developer receives no copy of your input or results.

### Compliance

- **Not legal or tax advice.** A registry answer is evidence of a check at a point in time, not a guarantee of a counterparty's status. Keep the consultation numbers and evidence records for your audit file.
- **Personal data:** sole traders' VAT names and addresses are personal data under UK GDPR and EU GDPR. Only check numbers you have a legitimate reason to verify, such as counterparty due diligence. Set `includeRegisteredDetails: false` if you only need valid/invalid and a match score. The Actor never collects emails or phone numbers. **You are the controller** of the numbers you submit and of the results; check them only for a lawful purpose that applies where you operate.
- **Independent tool:** not affiliated with, endorsed by or acting for HMRC, the European Commission (VIES), Companies House or GLEIF. A registry outage or error is reported as such and never shown as "invalid".
- **HMRC terms:** the HMRC API is provided "for the sole purpose of allowing traders to do due diligence on VAT-registered businesses". Use it only for that purpose, under your own Developer Hub terms of use.
- **Attribution:** every row carries the source attribution. VIES data is reusable under Commission Decision 2011/833/EU. GLEIF data is CC0. Companies House data should be used in line with its API terms.

*Sources checked 11 Oct 2026: VIES swagger contract (ec.europa.eu/assets/taxud/vow-information/swagger_publicVAT.yaml), HMRC Check a UK VAT number v2.0 OpenAPI spec (developer.service.hmrc.gov.uk), Companies House API reference and GLEIF API v1.*

Built by SiteVerdict (BharatFare Travel and Technologies Ltd, UK). For questions or feature requests, use the Apify Store issues tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/siteverdict/siteverdict-vat-validator/changelog.md

# Actor input Schema

## `numbers` (type: `array`):

One per line. Optional name and your own reference after a | (or ; or tab): <code>DE136695976 | Acme GmbH | INV-1001</code>. Use a country prefix for VAT numbers (DE, FR, EL/GR, GB, XI...). You can paste a whole spreadsheet column.

## `items` (type: `array`):

Alternative to the list above, e.g. from another Actor: <code>\[{"number": "FR40303265045", "name": "Example SA", "reference": "PO-7", "type": "vat", "country": "FR"}]</code>. <code>type</code> (vat / uk_company / lei) and <code>country</code> are optional.

## `checkMode` (type: `string`):

Format-only never calls a registry: it tells you which numbers are impossible (wrong length, bad check digit) at the lowest price.

## `numberType` (type: `string`):

Auto: 20-character codes with a valid ISO 17442 checksum are LEIs, numbers with a known VAT prefix are VAT numbers, 8-character numbers like 03977902 / SC123456 are UK company numbers.

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

Applied only to VAT numbers typed without a country prefix.

## `viesRequesterVat` (type: `string`):

Optional. When set, VIES returns a consultation number (request identifier) for each check - your proof to the tax authority that you checked. Example: DE123456789.

## `viesApproximateMatch` (type: `boolean`):

Sends your supplied name to VIES. Some countries that hide the registered name (e.g. Germany, Spain) can still answer VALID/INVALID for the name. A local fuzzy name score is always computed when the registry returns a name.

## `includeRegisteredDetails` (type: `boolean`):

Name and address exactly as returned by the registry. For sole traders this is personal data - untick if you only need valid/invalid and a match score.

## `storeEvidence` (type: `boolean`):

Saves each registry response (timestamped, with SHA-256) to the run's key-value store; the row's evidence_key points to it.

## `hmrcClientId` (type: `string`):

Needed to check GB VAT numbers. HMRC's 'Check a UK VAT number' API v2.0 requires your OWN HMRC Developer Hub application (free; subscribe it to the API). Without it, GB numbers are format/checksum-checked only.

## `hmrcClientSecret` (type: `string`):

The client secret of the same HMRC application. Stored encrypted by Apify; never logged or output.

## `hmrcEnvironment` (type: `string`):

Use sandbox while HMRC reviews your production access.

## `hmrcRequesterVrn` (type: `string`):

Optional. With it, HMRC returns a consultation number for each verified check.

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

Optional, free from developer.company-information.service.gov.uk (REST key). Needed to check UK company numbers against the register; otherwise they are format-checked only.

## `leiEnrichment` (type: `boolean`):

For UK company numbers found at Companies House, also look up any LEI registered against that number in the open GLEIF index (no extra charge).

## `concurrency` (type: `integer`):

Parallel checks. Registries are also rate-limited per source (VIES one request at a time per member state).

## `viesRequestsPerSecond` (type: `integer`):

Keep this low: VIES is a shared public service and answers MS_MAX_CONCURRENT_REQ when overloaded.

## `unavailableRetryRounds` (type: `integer`):

Member-state databases go offline (often at night or weekends). Numbers that hit an outage are retried at the end of the run. Still unavailable = status 'unavailable', never charged.

## `unavailableRetryDelaySecs` (type: `integer`):

Pause between the main pass and each retry round, giving the member-state database time to come back.

## `maxItems` (type: `integer`):

Process only the first N inputs.

## `sampleMode` (type: `boolean`):

Runs on recorded VIES/GLEIF responses and documented HMRC/Companies House examples so you can see the output format for free.

## Actor input object example

```json
{
  "numbers": [
    "IE6388047V | Google Ireland Limited | INV-1001",
    "DE143454214",
    "GB980780684",
    "03977902 | Google UK Limited"
  ],
  "checkMode": "registry",
  "numberType": "auto",
  "defaultCountry": "",
  "viesApproximateMatch": true,
  "includeRegisteredDetails": true,
  "storeEvidence": true,
  "hmrcEnvironment": "production",
  "leiEnrichment": false,
  "concurrency": 4,
  "viesRequestsPerSecond": 2,
  "unavailableRetryRounds": 2,
  "unavailableRetryDelaySecs": 60,
  "maxItems": 0,
  "sampleMode": false
}
```

# Actor output Schema

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

No description

## `output` (type: `string`):

No description

## `files` (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 = {
    "numbers": [
        "IE6388047V | Google Ireland Limited | INV-1001",
        "DE143454214",
        "GB980780684",
        "03977902 | Google UK Limited"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("siteverdict/siteverdict-vat-validator").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 = { "numbers": [
        "IE6388047V | Google Ireland Limited | INV-1001",
        "DE143454214",
        "GB980780684",
        "03977902 | Google UK Limited",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("siteverdict/siteverdict-vat-validator").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 '{
  "numbers": [
    "IE6388047V | Google Ireland Limited | INV-1001",
    "DE143454214",
    "GB980780684",
    "03977902 | Google UK Limited"
  ]
}' |
apify call siteverdict/siteverdict-vat-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,siteverdict/siteverdict-vat-validator"
        }
    }
}
```

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/4hUrIsa6PRqiRrBVq/builds/jXKgZWPa7Tr5PMThL/openapi.json
