# EU VAT Number Validator: Bulk VIES Checker (`offerastudio/eu-vat-number-validator`) Actor

Validate up to 10,000 EU VAT numbers in one run: offline format and check-digit test for all 27 EU countries plus Northern Ireland (XI), then the official VIES check with name, address, request date and an optional consultation number as proof. Unavailable answers are free.

- **URL**: https://apify.com/offerastudio/eu-vat-number-validator.md
- **Developed by:** [Offera Studio](https://apify.com/offerastudio) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 vat number checkeds

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

### What does EU VAT Number Validator do?

**EU VAT Number Validator** checks up to **10,000 EU VAT numbers in one run**, in two steps:

1. ✅ an **offline format and check-digit test** for all **27 EU member states plus Northern Ireland (XI)**, so typos are caught instantly and for free;
2. 🇪🇺 the **official VIES check** of the European Commission, which asks the tax administration that issued the number whether it is valid today.

For every number you get:

- the **normalised number** (`DE129274202`), the **country** and whether the **format is valid**, with a plain-English reason when it isn't;
- the **VIES status**: `valid`, `invalid`, `unavailable` or `not-checked`;
- the registered **name and address**, when the member state shares them;
- the **request date** of the check, and a **consultation number** as proof when you enter your own VAT number.

Paste numbers as they come: with or without the country prefix, with spaces, dots or dashes (`BE 0403.170.701`, `DE 129 274 202`, `ATU 102 230 06`).

### Who is this VAT checker for?

- **Finance and accounts receivable teams** that must check customers' VAT numbers before invoicing intra-EU supplies without VAT (reverse charge).
- **E-commerce and SaaS businesses** that sell to EU businesses and need to verify a buyer's VAT number at checkout or in bulk.
- **Procurement and supplier onboarding**: verify suppliers' VAT numbers and archive the result.
- **Data and CRM cleanup**: find typos and dead numbers in a customer list before a VAT audit.

### How the check works

**Step 1: offline format and check digit.** Each country has its own structure (Germany: 9 digits; the Netherlands: 9 digits + B + 2 digits; Ireland: 7 digits and 1–2 letters …) and most have a check digit. The Actor applies the published rules for all 28 VIES countries. A number that fails this test can't be valid, so by default it is **not sent to VIES and not charged**; the row says exactly what is wrong (wrong length, wrong characters, check digit doesn't match).

**Step 2: VIES.** Numbers that pass are checked in **VIES** (VAT Information Exchange System), the European Commission's official service. VIES forwards each request in real time to the database of the member state that issued the number. "Valid" means that tax administration confirms the number is active for intra-EU trade on the request date.

### Name and address: why some rows have none

VIES shows the name and address only where the member state allows it. **Germany and Spain, for example, never return them**; VIES then sends `---`, which the Actor turns into `null` with the note "Germany does not share the name and address through VIES". Other member states (Ireland, Czechia, Italy, France, Poland, Sweden …) usually do. A valid number without a name is still a valid number.

### UK (GB) numbers and Northern Ireland (XI)

**GB numbers are not in VIES since 1 January 2021 (Brexit).** The Actor still checks their format, but marks them `not-checked` (free) and points you to HMRC's "Check a UK VAT number" service. **Only Northern Ireland numbers, prefix `XI`**, are in VIES, because of the Protocol on Ireland and Northern Ireland; enter those with `XI`.

### When VIES is unavailable

Member state services go offline often: Italy most evenings, the Netherlands and Romania at weekends, many others for a few minutes every night. VIES then answers `MS_UNAVAILABLE`, `TIMEOUT` or, when too many people check the same country at once, `MS_MAX_CONCURRENT_REQ`. The Actor:

- retries each number up to 5 times with growing pauses (2, 5, 10 and 20 seconds);
- when a country fails twice in a row, sets its other numbers aside instead of hammering a service that is down;
- retries the set-aside numbers in rounds at the end of the run, for 2 minutes by default (**Keep retrying unavailable countries for**, up to 60);
- reports whatever is still unanswered as **`unavailable`, free**, with the VIES error code and a plain-English explanation. Run those numbers again later.

### Consultation number: proof of your check

Enter **your own VAT number** under **Your VAT number** and VIES returns a unique **consultation number** for each check. Keep it with the request date: it proves to a tax administration that you checked that number at that time and got that answer. VIES ties the consultation number to the requester number you give, so only use your own, valid VAT number. Confirming a customer's VAT number is one piece of evidence for a VAT-exempt intra-EU supply, not the only one.

### How to use it

1. Paste your VAT numbers into **VAT numbers**, one per line (or pasted from a spreadsheet column).
2. Optional: enter **Your VAT number** to get consultation numbers.
3. Optional: turn on **Format check only** for an instant, free offline check without VIES.
4. Click **Start**. The **Results** tab shows one row per number; **Proof** lists request dates and consultation numbers; **Details** shows format problems, VIES errors and retries.

Numbers without a country prefix use **Default country**; without one, a number is only used when exactly one country's rules fit it (the row then says `countrySource: detected`).

### Input example

```json
{
    "vatNumbers": ["DE129274202", "IE6388047V", "CZ 00 17 70 41", "FR 40 303 265 045", "GB980780684"],
    "requesterVatNumber": "DE123456789",
    "formatCheckOnly": false,
    "retryUnavailableMinutes": 5
}
```

### Output example

Real output from a run on 1 October 2026 (Google Ireland's VAT number as published in Google's imprint, Siemens AG's from its corporate information page, and a made-up number that passes the format check):

```json
[
    {
        "input": "IE6388047V",
        "position": 1,
        "vatNumber": "IE6388047V",
        "countryCode": "IE",
        "countryName": "Ireland",
        "countrySource": "prefix",
        "formatValid": true,
        "formatError": null,
        "viesStatus": "valid",
        "name": "GOOGLE IRELAND LIMITED",
        "address": "3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4",
        "requestDate": "2026-10-01T08:49:00.412Z",
        "consultationNumber": null,
        "requesterVatNumber": null,
        "viesError": null,
        "attempts": 1,
        "message": "Valid: Ireland's VAT database confirmed this number on 2026-10-01.",
        "checkedAt": "2026-10-01T08:49:00.432Z",
        "error": null
    },
    {
        "input": "DE129274202",
        "vatNumber": "DE129274202",
        "viesStatus": "valid",
        "name": null,
        "address": null,
        "message": "Valid: Germany's VAT database confirmed this number on 2026-10-01. Germany does not share the name and address through VIES."
    },
    {
        "input": "DE 999999995",
        "vatNumber": "DE999999995",
        "formatValid": true,
        "viesStatus": "invalid",
        "message": "Invalid: VIES says this number is not valid for cross-border trade within the EU on 2026-10-01. Check it with your customer; some member states only list numbers registered for intra-EU trade."
    }
]
```

(The second and third rows are shortened.) With **Your VAT number** filled in, `consultationNumber` contains a code such as `WAPIAAAA…`. A number that VIES couldn't check looks like this:

```json
{
    "vatNumber": "IT00905811006",
    "viesStatus": "unavailable",
    "viesError": "MS_UNAVAILABLE",
    "attempts": 7,
    "message": "No answer, not charged: Italy's VIES service was unavailable (MS_UNAVAILABLE). Member states take their service offline for maintenance, often at night or at weekends. Tried 7 times over about 2 minutes. Please try again later.",
    "error": "vies-unavailable"
}
```

### How much does it cost?

This Actor uses **pay per event**. You only pay when VIES gives a definitive answer:

| Event | Price |
| --- | --- |
| VAT number checked: VIES answered **valid** or **invalid** | **$0.002** per number |
| VIES or the member state unavailable or busy (`unavailable`) | **free** |
| Format check only, numbers that fail the format check, GB and non-EU numbers (`not-checked`) | **free** |

- 1,000 checked numbers cost **$2**; 10,000 cost **$20**.
- Duplicate numbers in one run are checked (and charged) once.
- Retries are free: a number is charged once, when the answer arrives.
- VIES itself is free; the price covers running the checks, retries and the offline validation.
- Apify also charges a tiny standard start fee per run (about $0.0000125 at the default 256 MB).
- Set **Maximum cost per run** in the run options and the Actor stops when it is reached.

### Limitations

- **"Invalid" is the member state's answer, not proof of fraud.** Some member states only list numbers registered for intra-EU trade, so a domestic-only business can show as invalid. Ask the customer and their tax office.
- **Speed and politeness.** The Commission designed VIES for single requests, so the Actor sends one request at a time per number, at most two at a time per member state and six overall, with short pauses. Expect about 1–4 numbers per second; 10,000 numbers of one country take roughly an hour.
- **Format rules** follow the structures published in the VIES FAQ and each country's published check-digit algorithm (cross-checked against the open-source python-stdnum library on more than 1,400 numbers). If a country introduces a new numbering scheme, turn off **Don't send numbers that fail the format check to VIES** to ask VIES anyway.
- **Unavailable numbers are not retried after the run.** Run them again later, or schedule the Actor.
- **No approximate matching** of name and address (a VIES feature only some member states support).
- **Not tax or legal advice.** VIES is provided by the European Commission without guarantee; the Commission's disclaimer applies.

### Fair use

VIES is meant for businesses that need to confirm their customers' or suppliers' VAT numbers, for example to invoice intra-EU supplies. Use this Actor for that purpose. Don't use it to build or resell databases of VAT numbers, names or addresses: the VIES disclaimer forbids extracting or re-publishing its data for other purposes.

### FAQ

#### Why is a valid number shown without a name?

The member state that issued it doesn't share names and addresses through VIES (for example Germany and Spain). The number is still valid.

#### Why did I get `unavailable`?

VIES or the member state's database didn't answer, even after several retries. That row is free. Try again later; maintenance windows are usually short.

#### Can I check UK VAT numbers?

GB numbers: format only, because VIES doesn't cover them since Brexit. Use HMRC's "Check a UK VAT number" service. Northern Ireland numbers: yes, with the prefix `XI`.

#### Do I need the country prefix?

No, but it helps. Without it, set **Default country**, or the Actor uses a number only when exactly one country's rules fit it.

#### Is the Greek prefix GR or EL?

VIES uses **EL**. You can type GR; the Actor converts it.

#### Can I run it on a schedule?

Yes. Save a task with your customer list and add a schedule in Apify Console, for example once a month before you file your recapitulative statement.

### More tools from the same developer

All pay-per-result, no proxy or login needed, built and maintained by the same developer:

**Website audits**

- [Website Accessibility Checker: WCAG 2.2 & EAA](https://apify.com/offerastudio/website-accessibility-audit): accessibility issues with fixes, SEO basics and security headers.
- [Cookie & Tracker Audit: GDPR Consent Checker](https://apify.com/offerastudio/cookie-tracker-audit): cookies and tracking tags that load before consent.
- [AI Crawler Access Checker: robots.txt & llms.txt](https://apify.com/offerastudio/ai-crawler-access-audit): which AI crawlers a site allows, plus llms.txt.
- [Website Change Monitor: Diffs, Prices & Alerts](https://apify.com/offerastudio/website-change-monitor): get a row only when a page changes, with a clean diff.

**Company data and compliance**

- [Company Contact Finder: Emails, Phones & Socials](https://apify.com/offerastudio/company-contact-finder): contact details published on company websites.
- [UK New Companies Feed: Companies House Daily](https://apify.com/offerastudio/uk-new-companies-feed): newly incorporated UK companies with sector filters.
- [LEI Corporate Tree: GLEIF Parents & Subsidiaries](https://apify.com/offerastudio/gleif-lei-corporate-tree): LEI lookup with parents, subsidiaries and a KYC summary.

**Market signals**

- [US WARN Layoff Notices: 12 States Daily Feed](https://apify.com/offerastudio/us-warn-layoff-notices): layoff and plant closure notices from official state sources.
- [US Product Recalls Monitor: FDA & CPSC Feed](https://apify.com/offerastudio/us-product-recalls-monitor): FDA and CPSC recalls in one feed, with severity.

### Feedback

A number that you know is valid but fails the format check, or a VIES answer that looks wrong? Open an issue on the **Issues** tab with the country and number.

# Changelog

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

# Actor input Schema

## `vatNumbers` (type: `array`):

Up to 10,000 VAT numbers, one per line. With or without the country prefix (DE129274202 or 129274202 with a default country); spaces, dots and dashes are ignored ("BE 0403.170.701" works). Greece: EL or GR. Northern Ireland: XI. Duplicates are checked once.

## `requesterVatNumber` (type: `string`):

Optional. Your own EU VAT number with prefix, e.g. DE123456789. VIES then returns a unique consultation number for each check, which you can keep as proof for your tax office that you checked the number on that date. VIES rejects requester numbers that are not valid.

## `formatCheckOnly` (type: `boolean`):

Only run the offline format and check-digit test, without asking VIES. Instant and free, but it can't tell whether a number is actually registered.

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

Country for numbers entered without a prefix. Leave empty to detect it: a number without prefix is used only if exactly one country's rules accept it.

## `skipViesIfFormatInvalid` (type: `boolean`):

On (recommended): a number with a wrong length or check digit can't be valid, so it isn't sent to VIES and isn't charged. Turn off to ask VIES anyway.

## `retryUnavailableMinutes` (type: `integer`):

Member state services are often offline for a while (maintenance, overload). Each number is retried a few times with growing pauses; numbers of a country that is still down are retried in rounds for this many minutes at the end of the run. Whatever is still unavailable then is reported as "unavailable" (free).

## Actor input object example

```json
{
  "vatNumbers": [
    "DE129274202",
    "IE6388047V",
    "CZ 00 17 70 41",
    "DE 132490588",
    "DE 11 94 29 301"
  ],
  "formatCheckOnly": false,
  "skipViesIfFormatInvalid": true,
  "retryUnavailableMinutes": 2
}
```

# Actor output Schema

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

No description

## `proof` (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 = {
    "vatNumbers": [
        "DE129274202",
        "IE6388047V",
        "CZ 00 17 70 41",
        "DE 132490588",
        "DE 11 94 29 301"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("offerastudio/eu-vat-number-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 = { "vatNumbers": [
        "DE129274202",
        "IE6388047V",
        "CZ 00 17 70 41",
        "DE 132490588",
        "DE 11 94 29 301",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("offerastudio/eu-vat-number-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 '{
  "vatNumbers": [
    "DE129274202",
    "IE6388047V",
    "CZ 00 17 70 41",
    "DE 132490588",
    "DE 11 94 29 301"
  ]
}' |
apify call offerastudio/eu-vat-number-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,offerastudio/eu-vat-number-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/oBv1D3RKRYXJoddhA/builds/S1g7K6ueed31o0bR3/openapi.json
