# VIES VAT Number Checker — bulk EU VAT validation (`fetchlab/vies-vat-checker`) Actor

Validate EU VAT numbers in bulk against the official VIES service. Format pre-check per country, company name and address, consultation number as proof, automatic retries when a member state is down.

- **URL**: https://apify.com/fetchlab/vies-vat-checker.md
- **Developed by:** [fetchlab](https://apify.com/fetchlab) (community)
- **Categories:** Business, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.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?

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

## VIES VAT Number Checker — bulk EU VAT validation

Validate one or thousands of **EU VAT numbers** against **VIES**, the European Commission's official VAT Information Exchange System. For each number you get: is it valid, the registered company name and address (where the member state publishes them), and optionally a **consultation number** — a reference to the VIES consultation when issued.

Built for the boring but mandatory part of intra-EU business: zero-rated B2B invoicing, customer onboarding, supplier master-data cleanup, and e-invoicing (Peppol) readiness checks.

### What it does better than calling VIES yourself

- **Any input format.** `BE0202239951`, `BE 0202.239.951`, `be-0202239951`, `GR…` or `EL…` for Greece, `XI…` for Northern Ireland. Bare numbers get a default country.
- **Format pre-check per country.** Malformed numbers are flagged as `invalid-format` without hitting VIES, which keeps large batches fast and avoids pointless errors.
- **Retries and rate-limit handling.** VIES and the national databases behind it go down or throttle regularly (`MS_UNAVAILABLE`, `MS_MAX_CONCURRENT_REQ`, timeouts). The Actor retries with backoff and reports the member state's availability, so `unavailable` never gets confused with `invalid`.
- **Consultation numbers.** Give your own VAT number and a check can return a VIES consultation number when the service issues one you can archive as evidence for your tax administration.
- **Clean, typed output.** One record per number, ready for a spreadsheet, a CRM import, an automation (Make, n8n, Zapier) or an AI agent.

### Input

| Field | Description |
|---|---|
| `vatNumbers` | List of VAT numbers with country prefix, one per line. |
| `defaultCountry` | Optional country code assumed for numbers typed without prefix. |
| `requesterVatNumber` | Optional. Your own VAT number; enables consultation numbers on valid results. |
| `skipViesForInvalidFormat` | Skip the VIES call for numbers that fail the format check (default on). |
| `concurrency` | Parallel requests, 1–5. Some member states (Belgium, for example) throttle concurrent requests; the default of 1 is safe. |
| `delayMs` | Pause between calls (default 200 ms). |

Example:

```json
{
    "vatNumbers": ["BE0202239951", "FR40303265045", "IT00743110157", "DE123456789"],
    "requesterVatNumber": "BE0202239951"
}
```

### Output

```json
{
    "input": "BE 0202.239.951",
    "normalized": "BE0202239951",
    "countryCode": "BE",
    "country": "Belgium",
    "vatNumber": "0202239951",
    "formatValid": true,
    "valid": true,
    "status": "valid",
    "name": "SA DPU PROXIMUS",
    "address": "Boulevard du Roi AlbertII 27\n1030 Schaerbeek",
    "consultationNumber": "WAPIAAAAaCcVvXld",
    "requestDate": "2026-09-13T19:56:01.120Z",
    "memberStateAvailability": "Available",
    "errorCode": null,
    "errorMessage": null,
    "checkedAt": "2026-09-13T19:56:01.400Z"
}
```

`status` is one of `valid`, `invalid`, `invalid-format`, `unavailable` (VIES or the member state could not answer, retry later) or `error`. Only `valid` and `invalid` are definitive answers from VIES.

### Pricing

Pay per event: **USD 0.003 per unique normalized VAT number with a definitive VIES answer** (`valid` or `invalid`). Invalid-format results, unavailable services and technical errors are not charged. Equivalent inputs share one check per run, including when processed concurrently; every input still gets its own row with `inputIndex`, `isDuplicate` and `duplicateOf`. The price per event is unchanged.

Runtime depends on VIES and member-state availability, retries and concurrency; no fixed throughput is guaranteed. A returned consultation number is evidence of the VIES request, not by itself a determination of VAT exemption or tax treatment.

### Using it from your code

```js
const run = await client.actor('fetchlab/vies-vat-checker').call({ vatNumbers: ['BE0202239951'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].valid, items[0].name);
```

```python
run = client.actor("fetchlab/vies-vat-checker").call(run_input={"vatNumbers": ["BE0202239951"]})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

Works with the Apify API, the Apify MCP server (AI agents can call it as a tool), Make, n8n, Zapier and scheduled runs.

### Notes and limits

- VIES answers only "is this number currently registered for VAT", as reported by the member state. Name and address are published by some states and withheld by others (Germany and Spain, for example, return no name).
- Great Britain (`GB`) numbers are no longer in VIES since Brexit; Northern Ireland uses `XI`.
- The service is operated by the European Commission and has scheduled and unscheduled downtime per member state. Some states (France in particular) throttle concurrent requests aggressively; the Actor retries up to six times with backoff and otherwise reports `unavailable` rather than guessing.

### Related

[Peppol Directory Lookup](https://apify.com/fetchlab/peppol-lookup) — is this company reachable on Peppol? · [Peppol BIS 3.0 Invoice Validator](https://apify.com/fetchlab/peppol-invoice-validator) — is this invoice compliant? More tools by [fetchlab](https://apify.com/fetchlab).

# Actor input Schema

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

One per line, with the country prefix: BE0202239951, NL123456789B01, FR40303265045, DE123456789, IT00743110157… Spaces, dots and dashes are ignored. GR and EL both work for Greece.

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

Optional. Country code assumed for numbers typed without a prefix (e.g. '0202239951' with BE).

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

Optional. When set, VIES returns a consultation number for each valid check — the official proof that you verified your customer's VAT number on that date (useful for intra-EU zero-rated invoicing).

## `skipViesForInvalidFormat` (type: `boolean`):

Numbers that fail the per-country format check are reported as 'invalid-format' without calling VIES (faster, cheaper).

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

Parallel requests. Some member states (e.g. Belgium) rate-limit concurrent requests; 1–2 is safe.

## `delayMs` (type: `integer`):

Pause after each VIES call, to stay polite with the service.

## Actor input object example

```json
{
  "vatNumbers": [
    "BE0202239951",
    "FR40303265045",
    "IT00743110157",
    "DE123456789"
  ],
  "skipViesForInvalidFormat": true,
  "concurrency": 1,
  "delayMs": 200
}
```

# Actor output Schema

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

All results.

# 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": [
        "BE0202239951",
        "FR40303265045",
        "IT00743110157",
        "DE123456789"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetchlab/vies-vat-checker").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": [
        "BE0202239951",
        "FR40303265045",
        "IT00743110157",
        "DE123456789",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fetchlab/vies-vat-checker").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": [
    "BE0202239951",
    "FR40303265045",
    "IT00743110157",
    "DE123456789"
  ]
}' |
apify call fetchlab/vies-vat-checker --silent --output-dataset

```

## MCP server setup

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

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/PyOolz13gdr0WyKiV/builds/Yc0wvqScSE0CrMFJj/openapi.json
