API Reference

Vatnode is a single-endpoint REST API that validates EU VAT numbers and returns the official VIES consultation number — the timestamped proof EU tax authorities accept at audit.

Base URL: https://vatnode.com

All requests and responses use JSON. All endpoints require HTTPS.

The API is live. Grab a free key and make your first call in under a minute.

Authentication

Vatnode uses an API key passed in the x-api-key header. Include your key in every request:

HTTP header
x-api-key: YOUR_API_KEY

Get your API key by joining the waitlist. Keys are issued per account and tied to your plan quota. Keep your key secret — never expose it in client-side code or public repos.

Quickstart

Validate a VAT number in one call. Most integrations are live in under an hour.

cURL
JavaScript
Python
PHP
# Validate an Irish VAT number curl -X POST https://vatnode.com/v1/validate \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"vat_number":"IE6388047V","requester_vat":"YOUR_OWN_VAT_NUMBER"}'
const response = await fetch('https://vatnode.com/v1/validate', { method: 'POST', headers: { 'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ vat_number: 'IE6388047V', requester_vat: 'YOUR_OWN_VAT_NUMBER' // optional but recommended }) }); const result = await response.json(); console.log(result.consultationNumber); // "WAPIAAAAW1234567"
import requests response = requests.post( 'https://vatnode.com/v1/validate', headers={'x-api-key': 'YOUR_API_KEY'}, json={ 'vat_number': 'IE6388047V', 'requester_vat': 'YOUR_OWN_VAT_NUMBER' } ) result = response.json() print(result['consultationNumber']) # "WAPIAAAAW1234567"
$ch = curl_init('https://vatnode.com/v1/validate'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'x-api-key: YOUR_API_KEY', 'Content-Type: application/json', ]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ 'vat_number' => 'IE6388047V', 'requester_vat' => 'YOUR_OWN_VAT_NUMBER', ])); $result = json_decode(curl_exec($ch), true); echo $result['consultationNumber']; // "WAPIAAAAW1234567"

POST /v1/validate

Validates an EU VAT number and returns the official VIES consultation number — the timestamped proof that you checked a customer's VAT ID against the EU's system.

Coverage: the EU-27 via VIES, plus non-VIES countries via their national registries — Norway (Brønnøysund) and Switzerland (the federal UID/MWST register) are both live. National-registry results return company name and address; consultationNumber is VIES-only.

POST https://vatnode.com/v1/validate
Before you copy-paste: replace YOUR_OWN_VAT_NUMBER with your company's real VAT number. VIES only issues a consultation number to a requester it can identify — a placeholder or another company's number gets the request rejected, which is the single most common reason a first integration returns no consultation number.

Request body

ParameterTypeRequiredDescription
vat_numberstringrequiredThe VAT number to validate. Include the 2-letter country prefix (e.g. IE6388047V, DE811907980). Spaces, dots and hyphens are stripped and the prefix is upper-cased automatically. Greece must be sent as EL, not GR.
requester_vatstringoptionalYour own VAT number — it must be a real, currently valid EU VAT number that belongs to you. Required by VIES to issue a consultation number. Send a made-up or expired number and VIES rejects the request (invalid_requester): you get no consultation number, and no company data. Omit it entirely and you still get a valid/invalid answer — just no audit evidence.

Example response — success

JSON · 200 OK
{ "valid": true, "vatNumber": "IE6388047V", "countryCode": "IE", "consultationNumber": "WAPIAAAAW1234567", "name": "GOOGLE IRELAND LIMITED", "address": "3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4", "requestDate": "2026-06-25+02:00", "timestamp": "2026-06-25T14:22:03.000Z" }

name and address are returned as published by each member state, and are null when a state doesn't publish them. Germany and Spain release validity only — that is VIES policy for those states, not a gap in the API. Full breakdown in Country coverage.

Example response — invalid VAT

JSON · 200 OK
{ "valid": false, "vatNumber": "DE000000000", "countryCode": "DE", "consultationNumber": null, "name": null, "address": null, "requestDate": "2026-06-25+02:00", "timestamp": "2026-06-25T14:22:10.000Z" }

When VIES is unavailable

VIES has frequent per-country outages. When the relevant member-state database is down, the API returns {"error":"vies_unavailable","retryable":true} rather than a misleading valid:false — so you can implement a short retry with exponential backoff instead of wrongly rejecting a real customer. Live per-country status is on the VIES status page.

Is there a fallback when a country's VIES is down? Yes — two layers, both clearly labelled, neither of them ever disguised as a fresh VIES check.

  1. Live national register — for the five states that publish a free official register (France, Poland, Finland, Czechia, Denmark) we re-check the number against that register in real time and flag it source: "national_vat_register_pl" and similar. It carries consultationNumber: null, because a national register doesn't issue one.
  2. 24h cache — everywhere else, if your own key validated that exact VAT number within the last 24 hours, we return your last confirmed result flagged source: "cache", cached: true, with the original cachedAt timestamp. Your checkout keeps working; you retry for a fresh consultation number once VIES recovers.

If neither applies, you get vies_unavailable with retryable: true — never a guessed valid: false. We never serve cached or third-party data as a fresh check, and we never enrich from a data broker and call it VIES. For countries VIES doesn't cover at all, the national register is the primary source — Norway is live today. Which countries are up right now: live status page. Full per-country detail: country coverage.

Country coverage — what each country returns

Every validation for the 27 EU member states + Northern Ireland (XI) confirms validity and, when you pass requester_vat, returns the official consultation number — always. Two things vary by country: whether the company name & address is released, and what happens if that country's VIES node goes down. The national-register fallback (green) is live where a country publishes a free official register.

CodeCountryName & addressIf VIES is down
ATAustria24h cache1
BEBelgium24h cache1
BGBulgaria24h cache1
HRCroatia24h cache1
CYCyprus24h cache1
CZCzechiaLive register · ARES2
DKDenmarkLive register · CVR2
EEEstonia24h cache1
FIFinlandLive register · PRH2
FRFranceLive register · SIRENE2
DEGermany— validity only324h cache1
ELGreece (EL5)24h cache1
HUHungary24h cache1
IEIreland24h cache1
ITItaly24h cache1
LVLatvia24h cache1
LTLithuania24h cache1
LULuxembourg24h cache1
MTMalta24h cache1
NLNetherlands24h cache1
PLPolandLive register · White List2
PTPortugal24h cache1
RORomania24h cache1
SKSlovakia24h cache1
SISlovenia24h cache1
ESSpain— validity only324h cache1
SESweden24h cache1
XINorthern Ireland24h cache1
NONorway · non-VIESNational register is the source4
CHSwitzerland · non-VIES— validity only6National register is the source6

Notes — how to read this table

Every EU-27 + XI row returns validity + the official VIES consultation number whenever you pass your own requester_vat — that's the audit evidence auditors ask for, and it's constant across every country here. Only the two columns above differ.

1 Standard fallback (24h cache). If a country's VIES node is down, we return your key's own last confirmed check from the past 24 hours, flagged source: "cache" — so your checkout keeps working and you keep the real consultation number. Retry for a fresh one when VIES recovers.

2 Live national-register fallback (FR, PL, FI, CZ, DK). These states publish a free official register, so during a VIES outage we confirm the number against it live. Two of them expose actual VAT status — Poland (VAT White List) and Czechia (ARES, stavZdrojeDph) — and are flagged source: "national_vat_register_pl" / _cz. The other three (France SIRENE, Finland PRH, Denmark CVR) confirm that the company is registered and active, which is strong evidence but not a VAT-status check; those are flagged source: "national_company_register_fr" and similar so you can tell the difference in your own logs. All five carry consultationNumber: null, because a national register doesn't issue one. Romania (ANAF) is the next one we want to add.

3 Germany (DE) & Spain (ES) release validity only. name and address come back empty for these two — it's their national policy, not a gap in the API. Every other state returns the registered company name and address.

4 Norway (NO) is not part of VIES. We validate it directly against the Brønnøysund national register (name + address; no consultation number, as that's a VIES-only concept).

5 Greece uses the EL prefix in VIES, even though its ISO country code is GR. 6 Switzerland (CH) is not in VIES either. We validate CHE… numbers against the Swiss federal UID/MWST register, which publishes VAT status only — no company name or address, and no consultation number. Send the number in any common form (CHE-116.281.710 MWST or CHE116281710); results carry source: "national_vat_register_ch". Send EL123456789 — that is the form VIES recognises. Casing and spaces don't matter (el 094 014 249 works); the prefix does.

Disclosure policy can change; we verify continuously and this table reflects live behaviour. Try any country yourself with the free checker.

The three response shapes

Same endpoint, same fields — only what each source releases differs. Check for error first, then read valid.

1. Most EU-27 — validity + consultation number + name + address:

JSON · 200 OK
{ "valid": true, "vatNumber": "IE6388047V", "countryCode": "IE", "name": "GOOGLE IRELAND LIMITED", "address": "GORDON HOUSE, BARROW STREET, DUBLIN 4", "consultationNumber": "WAPIAAAAW1234567", "requestDate": "2026-07-06+02:00", "timestamp": "2026-07-06T10:14:02.000Z" }

2. Germany & Spain — validity + consultation number; name/address empty (state releases validity only):

JSON · 200 OK
{ "valid": true, "vatNumber": "DE811907980", "countryCode": "DE", "name": null, // Germany discloses validity only "address": null, "consultationNumber": "WAPIAAAAW7654321", // still issued — this is your audit proof "requestDate": "2026-07-06+02:00", "timestamp": "2026-07-06T10:14:05.000Z" }

3. Non-VIES country (Norway) — validity + name + address from the national register; no consultation number (VIES-only concept), but the check is recorded in your audit log:

JSON · 200 OK
{ "valid": true, "vatNumber": "NO923609016", "countryCode": "NO", "name": "EQUINOR ASA", "address": "Forusbeen 50, 4035, STAVANGER, NO", "consultationNumber": null, // VIES-only; recorded in /v1/log instead "source": "national_registry_no", "requestDate": "2026-07-06T10:14:09.000Z", "timestamp": "2026-07-06T10:14:09.000Z" }

4. During a VIES outage (cache fallback) — if your key checked this exact VAT in the last 24h, we serve that last confirmed result flagged as cached, so your flow doesn't break. Retry for a fresh consultation number when VIES recovers:

JSON · 200 OK
{ "valid": true, "vatNumber": "DE811907980", "countryCode": "DE", "consultationNumber": "WAPIAAAAW7654321", // from your prior confirmed check "source": "cache", "cached": true, "cachedAt": "2026-07-06T09:02:00.000Z", // when the cached check actually ran "timestamp": "2026-07-06T10:14:12.000Z" }

Cache only ever serves your own key's prior confirmed check for the same VAT, within 24h — never third-party data, and always flagged. If there's no recent cached check, you get vies_unavailable to retry.

GET /v1/log Beta

Returns the validation history for your API key — every check is logged server-side, so this is your audit trail. Pass your key in the x-api-key header, same as /v1/validate.

GET https://vatnode.com/v1/log
ParameterTypeDescription
limitintegerNumber of records to return, newest first. Default: 100. Max: 1000.

Example response

JSON · 200 OK
{ "ok": true, "key": "vnd-…", "count": 128, "month_used": 12, "validations": [ { "vat_number": "DE811907980", "requester_vat": "YOUR_OWN_VAT_NUMBER", "valid": true, "consultation_number": "WAPIAAAAW1234567", "request_date": "2026-07-06T19:07:58Z", "created_at": "2026-07-06T19:07:58Z" } ] }

CSV export and date-range filtering are on the roadmap — email us if you need them now.

Response schema

All responses return HTTP 200 with a JSON body. Check the valid field and the presence of error to determine success or failure.

FieldTypeDescription
validbooleanWhether the VAT number is active and registered.
vatNumberstringThe VAT number that was validated.
countryCodestringISO 3166-1 alpha-2 country code derived from the VAT number prefix.
consultationNumberstring | nullThe official VIES consultation number (e.g. WAPIAAAAW1234567). null when the VAT is invalid, when you didn't pass a valid requester_vat, or when the answer came from a national register rather than VIES.
namestring | nullRegistered company name as published by the member state. null when the state doesn't release it (DE, ES) or the number is invalid.
addressstring | nullRegistered company address as published by the member state. null when unavailable. May contain newlines.
sourcestringOnly present when the answer did not come from a live VIES call: cache, national_vat_register_pl, national_company_register_fr, national_registry_no, etc. Absent means a fresh VIES result.
cachedbooleanPresent and true only when serving your key's own prior confirmed check during a VIES outage.
cachedAtstringISO 8601 timestamp of when the cached check actually ran against VIES.
requestDatestringDate of the VIES query (YYYY-MM-DD+offset).
timestampstringISO 8601 timestamp of when the validation was performed.
errorstringPresent only on failure — see error codes. When present, ignore valid.

Error codes

All responses return HTTP 200. When an error occurs, the response body contains an error field. Check for this before reading validation results.

Error codeDescription
invalid_api_keyMissing or invalid API key. Pass your key in the x-api-key header.
vies_unavailableThe member state's VIES node is temporarily down and no fallback applied. See VIES error codes explained for the full mapping. retryable: true is included — implement exponential backoff. Check the status page for which countries are affected.
rate_limit_exceededYour key's monthly quota is used up. The body includes limit, used and your plan. Quotas reset on the 1st.
invalid_requesterVIES rejected the requester_vat you sent — it must be a real, currently valid EU VAT number belonging to you. No consultation number is issued for a rejected requester, so we surface this instead of silently returning a weaker result. retryable: false.

Error response shape

JSON · 200 OK
{ "error": "invalid_api_key", "message": "Missing or invalid API key. Pass your key in the x-api-key header.", "docs": "https://vatnode.com/docs" }

Rate limits & quotas

Each API key has a monthly validation quota, enforced per key: Free 100 · Starter 2,000 · Growth 10,000 · Scale 50,000 (see the pricing page).

When a key exceeds its monthly quota, the API returns an error body instead of a validation result:

JSON
{ "error": "rate_limit_exceeded", "message": "Monthly limit of 100 validations reached on the free plan. Upgrade at https://vatnode.com/pricing", "limit": 100, "used": 101, "docs": "https://vatnode.com/docs" }

Check for the error field before reading validation results. Need a higher quota for evaluation? Email us and we'll raise your key's limit.

SDKs & libraries

Lightweight, dependency-free clients for Node.js, Python, and PHP are available now. Each wraps /v1/validate and /v1/log so you don't hand-roll HTTP.

Node.js
const Vatnode = require('./vatnode'); const vn = new Vatnode(process.env.VATNODE_KEY); const r = await vn.validate('IE6388047V', 'YOUR_OWN_VAT_NUMBER'); console.log(r.valid, r.consultationNumber);
Python
from vatnode import Vatnode vn = Vatnode(os.environ["VATNODE_KEY"]) r = vn.validate("IE6388047V", "YOUR_OWN_VAT_NUMBER") print(r["valid"], r["consultationNumber"])

Dependency-free clients for Node.js, Python and PHP are on GitHub: github.com/acirema792/vatnode-sdks. Need Ruby, Go, or a WooCommerce / Shopify plugin? Tell us →

MCP server New

Validate VAT numbers — with consultation numbers — directly inside Claude Desktop, Cursor, or any MCP-compatible AI client. Published on npm as vies-mcp.

claude_desktop_config.json
{ "mcpServers": { "vies": { "command": "npx", "args": ["-y", "vies-mcp"], "env": { "VATNODE_API_KEY": "vnd-your-key-here" } } } }

Tools: validate_vat (validity + company data + consultation number) and vies_status (live per-country VIES availability). Source: github.com/acirema792/vies-mcp.

Changelog

2026-09-17 — Switzerland live

CHE… VAT numbers are now validated against the Swiss federal UID/MWST register (source: "national_vat_register_ch"). Switzerland is outside VIES, so the register publishes VAT status only — no name, address or consultation number — and both CHE-116.281.710 MWST and CHE116281710 are accepted. Non-VIES coverage is now Norway and Switzerland. The free status page also gained an inline checker.

2026-09-16 — outage handling corrected

When a member state's VIES node was offline, the API could return valid: false instead of flagging the outage — VIES reports every failure mode, including downtime, as "not valid". The API now reads the underlying VIES status code: downtime, timeouts and rate-blocks route into the documented fallback chain (live national register where one exists, then your key's own 24-hour cache, then a retryable vies_unavailable), and only a genuine "not registered" answer returns valid: false. A rejected requester_vat now returns the new invalid_requester error rather than degrading quietly. Greek numbers are accepted with either the GR or EL prefix and normalised to EL, the form VIES recognises. The same corrections apply to the free VAT checker, which additionally now supports Norwegian organisation numbers.

2026-09-16 — documentation accuracy pass

Every code sample now uses a YOUR_OWN_VAT_NUMBER placeholder instead of a made-up requester VAT — sending an invalid requester is the most common reason a first integration gets no consultation number, and the old examples walked people straight into it. Response schema corrected: name, address and consultationNumber are null (not empty strings) when unavailable, and the source, cached, cachedAt and error fields are now documented. Added rate_limit_exceeded to the error table, documented the EL/GR prefix rule for Greece, and rewrote the outage section so it matches the two-layer fallback shown in country coverage — live national register for FR/PL/FI/CZ/DK, 24-hour cache elsewhere, with the VAT-status registers (PL, CZ) distinguished from the company registers (FR, FI, DK).

2026-07-17 — MCP server + country coverage

vies-mcp published on npm — VAT validation inside any MCP-compatible AI client. New country coverage reference documenting exactly what each member state returns. Docs examples switched to an Irish VAT number so the sample response matches real VIES behavior (DE/ES release validity only).

2026-06-25 — Early access

Initial API release for design partners. Endpoint: POST /v1/validate. VIES consultation number capture + company enrichment for all 27 EU member states. API key auth via x-api-key header.