10 min read

How to Validate EU VAT Numbers with the VIES API

VAT number validation is not optional. Since the 2020 Quick Fixes to the EU VAT Directive, a valid VAT identification number is a substantive requirement for zero-rating intra-community supplies under Art. 138 and for applying the reverse charge under Art. 196. If your buyer's VAT number is invalid and you do not charge VAT, you may be liable for the missing tax. This guide covers how to validate EU VAT numbers programmatically using the VIES API.

What is VIES?

VIES (VAT Information Exchange System) is the European Commission's official service for verifying the validity of VAT identification numbers issued by EU member states. It queries the national tax databases of all 27 member states in real time and returns whether a given VAT number is currently valid, along with the registered name and address.

The Commission provides both a web interface and a REST API. The old SOAP-only service has been replaced by a modern REST API that accepts JSON requests.

The VIES REST API

The current VIES API endpoint accepts POST requests with a JSON body:

POST https://ec.europa.eu/taxation_customs/vies/rest-api/check-vat-number

{
  "countryCode": "DE",
  "vatNumber": "123456789"
}

The response includes:

Important: The countryCode and vatNumber must be provided separately. Do not include the country prefix in the VAT number field. For DE123456789, use countryCode: "DE" and vatNumber: "123456789".

Python example

import requests

def validate_vat(country_code: str, vat_number: str) -> dict:
    """Validate an EU VAT number via the VIES REST API."""
    url = "https://ec.europa.eu/taxation_customs/vies/rest-api/check-vat-number"
    payload = {
        "countryCode": country_code.upper().strip(),
        "vatNumber": vat_number.strip().replace(" ", ""),
    }
    try:
        resp = requests.post(url, json=payload, timeout=10)
        resp.raise_for_status()
        data = resp.json()
        return {
            "valid": data.get("valid", False),
            "name": data.get("name", ""),
            "address": data.get("address", ""),
            "request_date": data.get("requestDate", ""),
        }
    except requests.Timeout:
        return {"valid": None, "error": "VIES timeout"}
    except requests.RequestException as e:
        return {"valid": None, "error": str(e)}

# Usage
result = validate_vat("DE", "123456789")
if result["valid"]:
    print(f"Valid: {result['name']}")
elif result["valid"] is None:
    print(f"VIES unavailable: {result['error']}")
else:
    print("Invalid VAT number")

JavaScript / Node.js example

async function validateVat(countryCode, vatNumber) {
  const url =
    "https://ec.europa.eu/taxation_customs/vies/rest-api/check-vat-number";
  const payload = {
    countryCode: countryCode.toUpperCase().trim(),
    vatNumber: vatNumber.trim().replace(/\s/g, ""),
  };

  try {
    const resp = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload),
      signal: AbortSignal.timeout(10000),
    });

    if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
    const data = await resp.json();

    return {
      valid: data.valid,
      name: data.name || "",
      address: data.address || "",
    };
  } catch (err) {
    return { valid: null, error: err.message };
  }
}

// Usage
const result = await validateVat("FR", "12345678901");
if (result.valid) console.log("Valid:", result.name);
else if (result.valid === null) console.log("VIES error:", result.error);
else console.log("Invalid VAT number");

VAT number format by country

Before calling VIES, validate the format locally. This catches obvious errors without an API call.

CountryCodeFormatExample
GermanyDE9 digitsDE123456789
FranceFR2 chars + 9 digitsFR12345678901
NetherlandsNL9 digits + B + 2 digitsNL123456789B01
ItalyIT11 digitsIT12345678901
SpainESletter + 7 digits + letterESX1234567X
IrelandIE7 digits + 1-2 charsIE1234567FA
PolandPL10 digitsPL1234567890
SwedenSE12 digitsSE123456789012

A comprehensive regex library by country is beyond the scope of this article, but the general approach is: strip the country prefix if present, validate character count and type against the country-specific pattern, then call VIES for authoritative validation.

Common pitfalls

1. VIES downtime

VIES queries individual member state databases, and these go offline regularly — sometimes for hours. When a specific country's database is unavailable, VIES returns an error for that country while other countries work fine. Build retry logic with exponential backoff, and decide what happens when validation fails: most tax advisors recommend treating the sale as B2C if you cannot validate the VAT number.

2. Rate limiting

The Commission does not publish official rate limits, but aggressive polling can result in temporary blocks. Cache validation results for a reasonable period (24-72 hours for active customers) and batch validations where possible.

3. Including the country prefix in the number

A common mistake: sending vatNumber: "DE123456789" instead of vatNumber: "123456789". Always strip the two-letter country prefix before calling the API.

4. Not storing the validation result

You need to prove that the VAT number was valid at the time of the transaction. Store the VIES response (valid/invalid, name, address, timestamp) alongside the transaction record. This is your evidence in an audit.

Best practices

UK VAT numbers (post-Brexit)

UK VAT numbers with the GB prefix are no longer in VIES since January 1, 2021. To validate UK VAT numbers, use HMRC's separate API. You need to register on the HMRC Developer Hub to obtain API credentials. The endpoint and response format differ from VIES, so your validation logic needs to handle both systems.

Frequently asked questions

Why is VAT number validation important?

Since the 2020 Quick Fixes, a valid VAT number is a substantive requirement for zero-rating intra-community supplies and applying the reverse charge. If the buyer's number is invalid, you may be liable for the VAT.

Is the VIES API free to use?

Yes. The VIES service is free, with no API keys or authentication required. However, it can be unreliable during peak hours or when individual member state databases are down.

How do I validate UK VAT numbers after Brexit?

UK VAT numbers (GB prefix) are no longer in VIES. Use HMRC's separate VAT API, which requires registration on the HMRC Developer Hub for API credentials.

DeterminedAI validates VAT numbers automatically as part of transaction processing. Every determination includes B2B/B2C classification with full audit trail.

Try DeterminedAI free →