VAT Validation

Validate EU VAT numbers against the official VIES database.

Endpoint

GET /v1/vat/{vatId}

Parameters

ParameterTypeRequiredDescription
vatIdstringYesThe VAT number to validate (e.g., IE6388047V)

Request

Terminal
curl https://api.vatnode.dev/v1/vat/IE6388047V \
  -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",
  "checkedAt": "2026-03-26T14:25:57.209Z",
  "source": "VIES",
  "checkId": "019d2a89-a5d9-7b97-b710-57b84604de2b",
  "countryVat": {
    "vatName": "Value Added Tax",
    "vatAbbr": "VAT",
    "currency": "EUR",
    "standardRate": 23,
    "reducedRates": [9, 13.5],
    "superReducedRate": null,
    "parkingRate": null,
    "ratesUpdatedAt": "2026-03-27"
  },
  "cache": {
    "hit": false,
    "ttlSeconds": 900
  }
}

Response Fields

FieldTypeDescription
validbooleantrue if the VAT number is valid and active
vatIdstringThe normalized VAT number
countryCodestringTwo-letter EU country code
countryNamestring | nullFull country name (e.g. "Finland")
companyNamestring | nullCompany name from VIES (may be null)
companyAddressstring | nullCompany address from VIES (may be null)
countryVat.vatNamestringOfficial local name of the tax (e.g. "Arvonlisävero", "Umsatzsteuer")
countryVat.vatAbbrstring | nullShort 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.ratesUpdatedAtstringDate the VAT rates were last updated from EC TEDB
checkIdstringUUID v7 uniquely identifying this check — matches the record in the audit log
checkedAtstringISO 8601 timestamp of the check
sourcestringData source: VIES or BZST (German fallback)
cache.hitbooleanWhether response came from cache
cache.ttlSecondsnumberSeconds until cache expires

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)

German VIES queries do not return company name or address. The companyName and companyAddress fields will be null.

BZST fallback: When the German VIES node is unavailable, vatnode automatically retries the request against the Bundeszentralamt für Steuern (BZST) — the German Federal Central Tax Office. If the fallback is used, the response will show "source": "BZST" instead of "source": "VIES". The validation result is equally authoritative.

Response
{
  "valid": true,
  "vatId": "DE134214316",
  "countryCode": "DE",
  "countryName": "Germany",
  "companyName": null,
  "companyAddress": null,
  "checkedAt": "2026-03-26T14:30:00.000Z",
  "source": "VIES",
  "checkId": "019d2a8c-5f3a-7d12-a901-bc23de456f78",
  "countryVat": {
    "vatName": "Umsatzsteuer",
    "vatAbbr": "MwSt",
    "currency": "EUR",
    "standardRate": 19,
    "reducedRates": [7],
    "superReducedRate": null,
    "parkingRate": null,
    "ratesUpdatedAt": "2026-03-27"
  },
  "cache": { "hit": false, "ttlSeconds": 900 }
}

Caching

Responses are cached to improve performance and reduce load on VIES:

  • Valid VAT numbers: Cached for 15 minutes
  • Invalid VAT numbers: Cached for 5 minutes

The cache object in the response indicates whether the response came from cache.

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}")