Developer guides

EU VAT number check API: VIES REST, error codes and what it cannot tell you

The European Commission checks EU VAT numbers for free through VIES, with no key and no bulk download; this guide shows the REST call, the failure modes you must retry, and what a "valid" answer does not mean. Source: Arcadium Data, data as of .

VIES (VAT Information Exchange System) is the only official way to learn whether an EU VAT number is registered right now. It does not hold the data itself: every request is forwarded to the tax authority of the member state in the number's prefix, and the answer comes back through the Commission. That one fact explains most of what goes wrong in production. The service is as available as the slowest national back end, and the amount of detail you get depends on the country.

This guide starts with the official route, including its limits. It then shows how to get the same check plus the national register status in one call from the Arcadium Data API.

The official route: VIES

Endpoints

The Commission offers a web form, a SOAP service (WSDL at ec.europa.eu/taxation_customs/vies/checkVatService.wsdl) and a REST API. The REST API is the simplest for new code:

No account or key is needed. In the responses we read, the JSON carries a validity flag (isValid), the date of the request, a userError text and, for most member states, the registered name and address. Check a live response for your own number before you rely on a field name; the Commission may change the schema.

curl

# Ireland: country prefix IE, number 6388047V
curl -s https://ec.europa.eu/taxation_customs/vies/rest-api/ms/IE/vat/6388047V

Python

import time
import requests

RETRY = {"MS_UNAVAILABLE", "MS_MAX_CONCURRENT_REQ", "TIMEOUT", "SERVICE_UNAVAILABLE"}

def vies_check(vat: str, tries: int = 4):
    """vat = 'IE6388047V' (prefix + number). Returns the VIES JSON, or None if VIES kept failing."""
    country, number = vat[:2].upper(), vat[2:].replace(" ", "")
    url = "https://ec.europa.eu/taxation_customs/vies/rest-api/ms/" + country + "/vat/" + number
    for attempt in range(tries):
        r = requests.get(url, timeout=30)
        if r.ok:
            data = r.json()
            if data.get("userError") not in RETRY:
                return data
        time.sleep(2 ** attempt)  # the member state is down or busy: back off
    return None

print(vies_check("IE6388047V"))

TypeScript

const RETRY = new Set(['MS_UNAVAILABLE', 'MS_MAX_CONCURRENT_REQ', 'TIMEOUT', 'SERVICE_UNAVAILABLE']);

export async function viesCheck(vat: string, tries = 4): Promise<Record<string, unknown> | null> {
  const country = vat.slice(0, 2).toUpperCase();
  const number = vat.slice(2).replace(/\s/g, '');
  const url = 'https://ec.europa.eu/taxation_customs/vies/rest-api/ms/' + country + '/vat/' + number;
  for (let attempt = 0; attempt < tries; attempt++) {
    const res = await fetch(url, { signal: AbortSignal.timeout(30_000) });
    if (res.ok) {
      const data = (await res.json()) as Record<string, unknown>;
      if (!RETRY.has(String(data.userError))) return data;
    }
    await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
  }
  return null;
}

Prefixes and number formats

Validate the shape before you call VIES; a malformed number wastes a request against a national back end that may already be struggling. The prefix is the ISO country code with two exceptions: Greece uses EL, not GR, and Northern Ireland uses XI (for goods only). Great Britain (GB) left VIES after Brexit, so a GB number cannot be checked here; HMRC runs its own check service for those.

CountryPrefixShape after the prefix
GermanyDE9 digits
FranceFR2 check characters + the 9-digit SIREN
ItalyIT11 digits
SpainES9 characters (letters allowed at either end)
NetherlandsNL9 digits + "B" + 2 digits
PolandPL10 digits
BelgiumBE10 digits
AustriaAT"U" + 8 digits
IrelandIE7 digits + 1 or 2 letters (older numbers differ)

Failure modes that are not "invalid"

VIES separates "this number is not registered" from "I could not ask". Treat the second as a retry, never as a rejection of your customer. The codes we see most are MS_UNAVAILABLE (the member state's system is down, often at night or during maintenance), MS_MAX_CONCURRENT_REQ (the member state refuses parallel load), TIMEOUT and a plain HTTP error from the gateway. Use a queue with exponential backoff, send one request at a time per country, and show "could not verify yet" in your product. There is no published per-key quota because there are no keys; the practical limit is how much the national back ends tolerate.

What "valid" does and does not mean

Reuse of the VIES output is covered by Commission Decision 2011/833/EU.

The fast route: one call that adds the register

The Arcadium Data route GET /v1/companies/verify calls VIES for you, handles the failure codes, caches the answer for 24 hours and, where the national register is open and anonymous, adds the register status in the same response. Today those registers are Norway (Brønnøysund), Finland (PRH/YTJ), France (recherche-entreprises plus stored BODACC insolvency notices) and the Czech Republic (ARES). For every other country the answer rests on the VAT registration alone and says so in statusBasis.

Calls on this page work without a key from one IP (10 requests a minute, 100 a day, short answers, point lookups). A free key lifts the limits: sign up. Routes, parameters and fields: OpenAPI.

curl

curl -s "https://api.arcadiumdata.io/v1/companies/verify?vat=IE6388047V"

Response (abridged)

{
  "status": "active",
  "statusBasis": "vat_registration",
  "country": "IE",
  "vatNumber": "IE6388047V",
  "legalName": "GOOGLE IRELAND LIMITED",
  "vat": {
    "vatNumber": "IE6388047V",
    "valid": true,
    "error": null,
    "requestDate": "2026-10-25T06:56:41.225Z",
    "source": "vies",
    "sourceUrl": "https://ec.europa.eu/taxation_customs/vies/rest-api/ms/IE/vat/6388047V",
    "cached": false
  },
  "notes": ["Status from the VAT registration only: the number is VAT-registered today (no register status)."]
}

vat.valid is null when VIES could not answer. vat.error then holds the code (MS_UNAVAILABLE, MS_MAX_CONCURRENT_REQ, TIMEOUT) and the top-level status is unknown: retry later. A sole trader or natural person answers not_company with nothing else, so no private name leaves the API.

With a national id instead of a VAT number, the register is asked live where it is open:

curl

curl -s "https://api.arcadiumdata.io/v1/companies/verify?id=923609016&country=NO"

Python

import time
import requests

def verify(vat: str):
    r = requests.get("https://api.arcadiumdata.io/v1/companies/verify?vat=" + vat, timeout=60)
    r.raise_for_status()
    d = r.json()
    if d["status"] == "unknown":  # VIES or the register did not answer
        return None
    return d

for attempt in range(3):
    result = verify("IE6388047V")
    if result:
        print(result["status"], result["statusBasis"], result["legalName"])
        break
    time.sleep(2 ** attempt)

TypeScript

type Verify = {
  status: string;
  statusBasis: string;
  legalName: string | null;
  vat: { valid: boolean | null; error: string | null } | null;
};

const res = await fetch('https://api.arcadiumdata.io/v1/companies/verify?vat=IE6388047V', {
  headers: { Authorization: 'Bearer ' + process.env.ARCADIUM_API_KEY }, // optional: leave out for the anonymous tier
});
const body = (await res.json()) as Verify;
if (body.status === 'unknown') console.log('retry later', body.vat?.error);
else console.log(body.status, body.statusBasis, body.legalName);

To go from a VAT number to the company's website, registry ids and LEI, call GET /v1/companies/resolve with the number as id; the next guide covers it. The same lookups run without code in the company lookup and through the MCP server, so an AI agent can ask for a live check in plain language.

What we do not do: we do not search VIES by name (it cannot), we do not return officers or owners, and for Germany and Spain the legal name stays empty because VIES withholds it. A verify call is one outbound check, so it has its own, lower anonymous daily budget than the stored-data routes.

Comparison

VIES directArcadium Data /v1/companies/verify
Key or accountNoneNone for the anonymous tier; free key for more
Retries and error codesYou write themReturned as vat.error with status: unknown
CachingNone24 hours (cached)
Register statusNot includedNorway, Finland, France, Czech Republic
Sole tradersName may be a private personAnswers not_company, nothing else
Name from Germany or Spain---Empty
Great BritainNot coveredNot a VAT check; see the Companies House guide in the backlog
Search by name, bulk fileNoNo (name lookups: the resolve route)
Evidence for a tax authorityConsultation number routeNot a substitute; use VIES with your own VAT number

Get the data without the plumbing

Arcadium Data serves these datasets from one REST API and one MCP server, with sources, licences and dates on every answer. No key is needed to try the routes in this guide.

Sources

Last updated 2026-10-25. This guide is ours and independent of the organisations it describes. Found a mistake? Tell us and we correct it.

Questions

Is there an official VIES API and does it need a key?

Yes. VIES has a SOAP service and a REST API at ec.europa.eu/taxation_customs/vies/rest-api. Neither needs an account or a key. Availability depends on the member state that owns the number.

Why does VIES say the service is unavailable for some numbers?

Each request is forwarded to the member state of the number. When that national system is down or busy, VIES returns MS_UNAVAILABLE, MS_MAX_CONCURRENT_REQ or a timeout. It is not a statement about the number: retry later with backoff.

Can I check a UK VAT number in VIES?

No. Great Britain left VIES after Brexit. Only Northern Ireland numbers (prefix XI, goods) are still covered. HMRC offers a separate service for GB numbers.

Does a valid VAT number mean the company is active?

No. It means the number is registered for VAT today. A company in liquidation can still hold a registration. Use the national register status as well; our verify route returns it for Norway, Finland, France and the Czech Republic.

Can I look up a VAT number by company name?

Not in VIES. For name to VAT lookups use a national register or the resolve route of our API (GET /v1/companies/resolve with name and country), which answers from stored register, legal-notice and GLEIF data.

Cite as: Arcadium Data, "EU VAT number check API: VIES REST, error codes and what it cannot tell you", https://arcadiumdata.io/guides/eu-vat-number-check-vies-api/, data as of 2026-10-25.