VAT Validation
Validate EU VAT numbers against the official VIES database.
Endpoint
GET /v1/vat/{vatId}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| vatId | string | Yes | The VAT number to validate (e.g., IE6388047V) |
Request
curl https://api.vatnode.dev/v1/vat/IE6388047V \
-H "Authorization: Bearer vat_live_your_key"Response
Success Response (200 OK)
{
"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
| Field | Type | Description |
|---|---|---|
| valid | boolean | true if the VAT number is valid and active |
| vatId | string | The normalized VAT number |
| countryCode | string | Two-letter EU country code |
| countryName | string | null | Full country name (e.g. "Finland") |
| companyName | string | null | Company name from VIES (may be null) |
| companyAddress | string | null | Company address from VIES (may be null) |
| countryVat.vatName | string | Official local name of the tax (e.g. "Arvonlisävero", "Umsatzsteuer") |
| countryVat.vatAbbr | string | null | Short abbreviation (e.g. "ALV", "MwSt", "TVA") |
| countryVat.currency | string | ISO 4217 currency code (e.g. "EUR", "BGN") |
| countryVat.standardRate | number | Standard VAT rate in percent (e.g. 25.5) |
| countryVat.reducedRates | number[] | Reduced VAT rates, empty array if none |
| countryVat.superReducedRate | number | null | Super-reduced rate (CY, ES, FR, GR, IT, LU, PL, PT) |
| countryVat.parkingRate | number | null | Parking rate (transitional, only some countries) |
| countryVat.ratesUpdatedAt | string | Date the VAT rates were last updated from EC TEDB |
| checkId | string | UUID v7 uniquely identifying this check — matches the record in the audit log |
| checkedAt | string | ISO 8601 timestamp of the check |
| source | string | Data source: VIES or BZST (German fallback) |
| cache.hit | boolean | Whether response came from cache |
| cache.ttlSeconds | number | Seconds until cache expires |
VAT Number Format
VAT numbers must include the two-letter country code prefix. Here are some examples:
| Country | Format | Example |
|---|---|---|
| Germany | DE######### | DE123456789 |
| Finland | FI######## | FI12345678 |
| France | FRXX######### | FR12345678901 |
| Netherlands | NL#########B## | NL123456789B01 |
| Spain | ESX######## | 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.
{
"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)
{
"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)
{
"error": {
"code": "VIES_UNAVAILABLE",
"message": "VIES service is temporarily unavailable",
"requestId": "req_abc123"
}
}Code Examples
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
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}")