# VIES VAT Checker — Bulk VAT Number Validation (`devilscrapes/vies-vat-number-validator`) Actor

Bulk VAT number validation against the official, keyless VIES REST API. This EU VAT validator accepts numbers in any common format and returns one row each: validity, registered name and address where disclosed, and a clear skip reason. A VIES VAT checker built for whole lists.

- **URL**: https://apify.com/devilscrapes/vies-vat-number-validator.md
- **Developed by:** [DevilScrapes](https://apify.com/devilscrapes) (community)
- **Categories:** Developer tools
- **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?

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

<div align="center">
  <img src=".actor/icon.svg" width="160" alt="Devil Scrapes mark" />

## VIES VAT Number Validator (Bulk)

**💰 $1.20 / 1 000 VAT numbers checked**  ·  pay only for results  ·  no credit card to try

*We do the dirty work so your dataset stays clean.* 😈

A bulk VAT number check and VAT number validation API wrapper around the official, keyless VIES REST API. Feed VAT numbers in any common format (glued, spaced, or structured) and get one row back per number: validity, registered name/address where disclosed, and a clear skip reason for anything unparseable.

</div>

***

### 🎯 What this scrapes

A customer hands us a list of VAT numbers — glued, spaced, or structured pairs, mixed together — and we return one row per number: validity, the registered company name and address where the member state discloses it, and a clear skip reason for anything we can't parse or that VIES can't complete. Think of it as a VIES VAT checker and EU VAT validator in one: built for a recurring compliance/onboarding batch job running VAT number validation against a customer list, not a one-off lookup — the product optimizes for cheap, high-volume, fault-isolated throughput. One bad entry in a 5,000-row batch never fails the run — it lands as its own explained row and everything else still ships.

### 🔥 What we handle for you

- 🧾 **Any input shape, one clean pair** — glued (`DE811907980`), spaced (`DE 811907980`), or structured (`{"country":"DE","number":"811907980"}`) all normalize to the same `(country, number)` before we ever call VIES.
- 🧱 **Bounded, polite concurrency** — VIES is a shared EC service that throttles hard under load, so we cap in-flight requests and back off automatically on `429`/`5xx` instead of hammering it.
- ✅ **Clean negatives are not errors** — an invalid VAT number is a normal, useful answer. Every entry — valid, cleanly invalid, or unparseable — lands as its own row with a clear status, so one bad number never fails your whole batch.
- 🕵️ **Optional service-status pre-flight** — turn on `checkServiceStatus` to see which member states are down before you burn a run against unavailable infrastructure.
- 🧊 **Typed, validated dataset rows** — Pydantic-checked, one row per requested number, every time — the row count you get back always matches the row count you sent in.
- 💰 **Pay-Per-Event pricing** — priced for volume, not per-lookup margin. You always know what a batch costs before you run it.

### 💡 Use cases

- Customer onboarding — validate a new B2B customer's VAT number before invoicing them without VAT.
- Recurring compliance sweeps — re-validate an entire customer list on a schedule to catch deregistered numbers.
- Invoice/AR cleanup — batch-check VAT numbers on file before a VAT audit.
- CRM/ERP enrichment — attach the registered company name and address VIES discloses to existing records.

### ⚙️ How to use it

1. Click **Try for free** at the top of the page.
2. Fill in the input form — most fields have sensible defaults.
3. Click **Start**. Output streams into the run's dataset.
4. Export from **Storage → Dataset** as JSON, CSV, or Excel — or fetch via the API.

### 📥 Input

| Field | Type | Required | Default | Notes |
|---|---|:--:|---|---|
| `vatNumbers` | `array` | **yes** | \['DE811907980', 'IE 6388047V', {'country': 'NL', 'number': '810462215B01'}] | VAT numbers to validate, one per list item. Each item is either a glued string ('DE811907980'), a spaced string ('DE… |
| `checkServiceStatus` | `boolean` | no | False | If enabled, calls the VIES check-status endpoint once at the start of the run and surfaces any member-state outage… |
| `maxConcurrency` | `integer` | no | 3 | Cap on concurrent requests to VIES. Kept low by design — VIES is a shared public EC service that rejects excessive… |
| `proxyConfiguration` | `object` | no | {} | Apify Proxy configuration. Present per org standard — VIES is a public keyless API, so no proxy is used unless you… |

#### Example input

```json
{
  "vatNumbers": [
    "DE811907980",
    "IE 6388047V",
    {
      "country": "NL",
      "number": "810462215B01"
    }
  ],
  "checkServiceStatus": false,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

### 📤 Output

Every row is one dataset item.

| Field | Type | Notes |
|---|---|---|
| `countryCode` | `string` | Parsed from input / echoed from VIES. |
| `vatNumber` | `string` | Normalised input (country prefix stripped, whitespace removed). |
| `isValid` | `boolean` | VIES response 'valid'/'isValid' field. Only null for skipped rows. |
| `name` | `string` | VIES response 'name'; the literal '---' (DE/ES policy) is normalised to null. |
| `address` | `string` | VIES response 'address'; same '---' normalisation as name. |
| `requestDate` | `string` | VIES response 'requestDate', ISO-8601 passthrough. |
| `skipped` | `boolean` | True when the input entry could not be parsed or the request could not complete after retries. |
| `skipReason` | `string` | Human-readable reason, only set when skipped=true. |

#### Example output

```json
{
  "countryCode": "IE",
  "vatNumber": "6388047V",
  "isValid": true,
  "name": "GOOGLE IRELAND LIMITED",
  "address": null,
  "requestDate": "2026-09-06+02:00",
  "skipped": false,
  "skipReason": null
}
```

### 💰 Pricing

Pay-Per-Event — you pay only when these events fire:

| Event | USD | What it is |
|---|---:|---|
| `actor-start` | $0.2 | One-off warm-up charge per run |
| `vat-number-checked` | $0.001 | PPE event |

Example: 1 000 VAT numbers checked at the rates above ≈ **$1.20**. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.

### 🚧 Limitations

- VIES covers EU member states only — no UK post-Brexit, Norwegian, or Swiss tax-ID formats.
- Some member states (confirmed: DE, ES) never return a registered company name or address by policy — those fields come back `null` for those countries even on a valid VAT number, not a scraping gap.
- Concurrency is capped at 5 requests in flight by design — VIES is a shared public EC service and rejects excessive parallel load.
- No caching or dedup of previously-seen VAT numbers across runs — every run re-checks every number you send.

### ❓ FAQ

**Why do some rows have a null name and address even though the VAT number is valid?**

A handful of EU member states (Germany and Spain, confirmed) never disclose the registered company name or address through VIES, by that country's own policy — we normalize their internal '---' placeholder to `null` so it's clear this is a policy limit, not missing data.

**Is an invalid VAT number a failed run?**

No. A VAT number VIES reports as invalid is a normal, useful answer — the run still succeeds, and that row simply says `isValid: false`.

**What happens if one VAT number in my batch is malformed?**

It lands as its own row with `skipped: true` and a human-readable `skipReason` explaining why — the rest of your batch is processed normally.

**Can I check if VIES itself is having an outage before I run a large batch?**

Yes — enable `checkServiceStatus` and we call VIES's own status endpoint once at the start of the run and surface any member-state outage.

### 💬 Your feedback

Spotted a bug, hit a weird edge case, or need a new field? Open an
issue on the Actor's **Issues** tab on Apify Console — we ship
fixes weekly and we read every report.

***

<div align="center">

Built by **[Devil Scrapes](https://apify.com/DevilScrapes)** 😈 — a small fleet of
opinionated public-data Actors. Honest pricing, real engineering, zero fine print.

</div>

# Actor input Schema

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

VAT numbers to validate, one per list item. Each item is either a glued string (<code>"DE811907980"</code>), a spaced string (<code>"DE 811907980"</code>), or a structured object (<code>{"country": "DE", "number": "811907980"}</code>).

## `checkServiceStatus` (type: `boolean`):

If enabled, calls the VIES check-status endpoint once at the start of the run and surfaces any member-state outage before processing entries.

## `maxConcurrency` (type: `integer`):

Cap on concurrent requests to VIES. Kept low by design — VIES is a shared public EC service that rejects excessive parallel load.

## `proxyConfiguration` (type: `object`):

Apify Proxy configuration. Present per org standard — VIES is a public keyless API, so no proxy is used unless you explicitly enable one here.

## Actor input object example

```json
{
  "vatNumbers": [
    "DE811907980",
    "IE 6388047V",
    {
      "country": "NL",
      "number": "810462215B01"
    }
  ],
  "checkServiceStatus": false,
  "maxConcurrency": 3,
  "proxyConfiguration": {}
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# 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": [
        "DE811907980",
        "IE 6388047V",
        {
            "country": "NL",
            "number": "810462215B01"
        }
    ],
    "checkServiceStatus": false,
    "maxConcurrency": 3,
    "proxyConfiguration": {}
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/vies-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": [
        "DE811907980",
        "IE 6388047V",
        {
            "country": "NL",
            "number": "810462215B01",
        },
    ],
    "checkServiceStatus": False,
    "maxConcurrency": 3,
    "proxyConfiguration": {},
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/vies-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": [
    "DE811907980",
    "IE 6388047V",
    {
      "country": "NL",
      "number": "810462215B01"
    }
  ],
  "checkServiceStatus": false,
  "maxConcurrency": 3,
  "proxyConfiguration": {}
}' |
apify call devilscrapes/vies-vat-number-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,devilscrapes/vies-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/85NUxdRnyOp8Cp4IY/builds/lGgHAdpY1dRida4g3/openapi.json
