VAT Validation

Validate EU VAT numbers against the official VIES database.

Audit-proof by design

Every response includes a consultationNumber — the EU Commission-issued reference for the exact VIES check — and a permanent checkId + verifiedAt timestamp. Store these alongside your invoice records as audit evidence. Requires requesterCountryCode + requesterVatNumber query params to obtain the consultation number.

Endpoint

GET /v1/vat/{vatId}

Parameters

ParameterTypeRequiredDescription
vatIdstringYes (path)The VAT number to validate (e.g., IE6388047V)
requesterCountryCodestringNo (query)Your two-letter EU country code (e.g. FI). Required together with requesterVatNumber to obtain a VIES consultation number.
requesterVatNumberstringNo (query)Your own EU VAT number without the country prefix (e.g. 12345678). When provided alongside requesterCountryCode, vatnode calls VIES checkVatApprox and returns a consultationNumber in the response.
forcebooleanNo (query)Set to true to bypass the Redis cache and force a fresh VIES lookup. Useful for high-value checks where freshness matters.

Request

Basic request
curl https://api.vatnode.dev/v1/vat/IE6388047V \
  -H "Authorization: Bearer vat_live_your_key"
With consultation number (audit)
curl "https://api.vatnode.dev/v1/vat/IE6388047V?requesterCountryCode=FI&requesterVatNumber=12345678" \
  -H "Authorization: Bearer vat_live_your_key"

Response

Success Response (200 OK)

Response
{
  "valid": true,
  "vatId": "IE6388047V",
  "countryCode": "IE",
  "countryName": "Ireland",
  "companyName": "GOOGLE IRELAND LIMITED",
  "companyAddress": "3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4",
  "companyRegistrationDate": null,
  "companyForm": null,
  "industryDescription": null,
  "registryCode": null,
  "registryCodeName": null,
  "verifiedAt": "2026-03-26T14:25:57.209Z",
  "checkId": "019d2a89-a5d9-7b97-b710-57b84604de2b",
  "consultationNumber": "WAPIAAAAZ27qPadm",
  "source": "VIES",
  "countryVat": {
    "vatName": "Value Added Tax",
    "vatAbbr": "VAT",
    "currency": "EUR",
    "standardRate": 23,
    "reducedRates": [9, 13.5],
    "superReducedRate": null,
    "parkingRate": null,
    "vatNumberFormat": "IE + 7 digits + 1–2 letters",
    "vatNumberPattern": "^IE\d{7}[A-W][A-IW]?$|^IE\d[A-Z+*]\d{5}[A-W]$",
    "countryVatUpdatedAt": "2026-03-27"
  },
}

Response Fields

FieldTypeDescription
validbooleantrue if the VAT number is valid and active
vatIdstringThe normalized VAT number
countryCodestringTwo-letter EU country code
countryNamestringFull country name (e.g. "Finland")
companyNamestring | nullCompany name from VIES (may be null)
companyAddressstring | nullCompany address from VIES (may be null)
companyRegistrationDatestring | nullDate the company was registered (ISO 8601 date). Populated from national registries where available (SE, FR, CZ, FI, DK, PL, DE…); null otherwise.
companyFormstring | nullLegal form of the company (e.g. "AB", "GmbH", "SAS"). Populated from national registries where available; null otherwise.
industryDescriptionstring | nullIndustry or business activity description from national registry (e.g. NACE/SNI code label). Populated where available; null otherwise.
registryCodestring | nullNational company registry identifier (e.g. Y-tunnus for FI, SIREN for FR, Registrikood for EE). Derived from the VAT number where the mapping is known; fetched from national registry for EE and LT. Null for DE and countries without a public registry API.
registryCodeNamestring | nullName of the registry identifier type (e.g. "Y-tunnus", "SIREN", "CVR", "Registrikood"). Null if registryCode is null.
countryVat.vatNamestringOfficial local name of the tax (e.g. "Arvonlisävero", "Mehrwertsteuer")
countryVat.vatAbbrstringShort abbreviation (e.g. "ALV", "MwSt", "TVA")
countryVat.currencystringISO 4217 currency code (e.g. "EUR", "BGN")
countryVat.standardRatenumberStandard VAT rate in percent (e.g. 25.5)
countryVat.reducedRatesnumber[]Reduced VAT rates, empty array if none
countryVat.superReducedRatenumber | nullSuper-reduced rate (CY, ES, FR, GR, IT, LU, PL, PT)
countryVat.parkingRatenumber | nullParking rate (transitional, only some countries)
countryVat.vatNumberFormatstringHuman-readable VAT number format (e.g. "DE + 9 digits")
countryVat.vatNumberPatternstringRegex for local format validation.
countryVat.countryVatUpdatedAtstringDate the VAT rates were last updated from EC TEDB
checkIdstringUUID v7 uniquely identifying this check — matches the record in the audit log
verifiedAtstringISO 8601 timestamp of the check
consultationNumberstring | nullEU Commission-issued reference for this VIES check (the VIES requestIdentifier). Present when requesterCountryCode and requesterVatNumber are supplied and VIES is used directly. Null when served from cache, when national fallback was used, or when no requester was provided. Store this alongside your invoice record as audit evidence.
sourcestringIdentifies which system produced the result: VIES for the normal path, or a national registry code when VIES fell back (e.g. BZST for DE, MF_PL for PL, ANAF_RO for RO).

VAT Number Format

VAT numbers must include the two-letter country code prefix. Here are some examples:

CountryFormatExample
GermanyDE#########DE123456789
FinlandFI########FI12345678
FranceFRXX#########FR12345678901
NetherlandsNL#########B##NL123456789B01
SpainESX########ESA12345678

Normalization

VAT numbers are automatically normalized:

  • Converted to uppercase
  • Whitespace and dashes removed
  • Leading/trailing spaces trimmed

All of these are equivalent:

IE6388047V
IE 6388047V
IE-6388047V
  IE6388047V  

Country-Specific Notes

Germany (DE) and Spain (ES)

German and Spanish VIES queries do not return company name or address. The companyName and companyAddress fields will always be null for German and Spanish VAT numbers.

National fallbacks

For select EU countries, vatnode automatically falls back to official national tax authority APIs when the VIES member-state node is unavailable. The fallback is fully transparent — the response format is identical and the result is equally authoritative.

Error Responses

Invalid Format (400)

Response
{
  "error": {
    "code": "INVALID_FORMAT",
    "message": "Invalid VAT ID format. Expected format: country code (2 letters) followed by VAT number",
    "requestId": "req_abc123"
  }
}

VIES Unavailable (503)

Response
{
  "error": {
    "code": "VIES_UNAVAILABLE",
    "message": "VIES service is temporarily unavailable",
    "requestId": "req_abc123"
  }
}

Code Examples

JavaScript

JavaScript
async function validateVat(vatId) {
  const response = await fetch(`https://api.vatnode.dev/v1/vat/${vatId}`, {
    headers: {
      'Authorization': `Bearer ${process.env.VATNODE_API_KEY}`
    }
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error.message);
  }

  return response.json();
}

// Usage
try {
  const result = await validateVat('IE6388047V');
  if (result.valid) {
    console.log(`Valid: ${result.companyName}`);
  }
} catch (error) {
  console.error('Validation failed:', error.message);
}

Python

Python
import requests
import os

def validate_vat(vat_id):
    response = requests.get(
        f'https://api.vatnode.dev/v1/vat/{vat_id}',
        headers={'Authorization': f'Bearer {os.environ["VATNODE_API_KEY"]}'}
    )
    response.raise_for_status()
    return response.json()

# Usage
try:
    result = validate_vat('IE6388047V')
    if result['valid']:
        print(f"Valid: {result['companyName']}")
except requests.HTTPError as e:
    print(f"Validation failed: {e}")