VIES API for Developers — Validate EU VAT Numbers via REST
vatnode is a VIES API for developers: a REST layer over the European Commission’s VIES service that turns EU VAT number validation into a single authenticated HTTPS call. This page is the integration reference — the endpoint, the response contract, the audit trail, and how vatnode behaves when VIES itself is unavailable.
One authenticated REST call returns a validated EU VAT number with the trader’s company name and address, a VIES consultation number for your audit trail, and a fallback to national tax-authority and company-registry data when VIES is down — no SOAP client to build, no per-member-state quirks to babysit.
What the VIES API Is
VIES (VAT Information Exchange System) is the European Commission’s official service for verifying VAT identification numbers issued by EU member states. It is the authoritative source: each check is answered by the tax administration of the member state that issued the number, routed through the Commission’s central gateway. If you need to confirm that a customer’s VAT number is genuinely registered — for reverse-charge invoicing, B2B onboarding, or compliance evidence — VIES is the register that matters. See what the VIES system is for background.
The raw VIES service is SOAP-based and unauthenticated. You send an XML envelope over HTTPS, parse an XML response, and handle behaviors that are awkward in production: there is no API key or account, informal rate limits apply, and availability is per member state — any single country’s register can return “member state unavailable” while the rest work, and the whole gateway has scheduled and unscheduled downtime. There is no caching, no structured company-data contract, and no persistent record of what you checked and when. Calling VIES directly means building and maintaining all of that yourself, per country, and absorbing the downtime.
What vatnode Adds on Top of VIES
vatnode wraps VIES in the things a production integration needs. If your current path is a hand-rolled SOAP client, this is the VIES API alternative it replaces.
- REST JSON over HTTPS — a plain GET request with a JSON response.
- Bearer authentication — one API key per environment, with quotas and usage tracking.
- Caching — recent results are served from cache (source: "CACHE") instead of re-hitting VIES.
- A never-null structured contract — the same flat shape every time; absent fields are null, never missing.
- National-registry fallback — a national source answers when VIES is unavailable, and tells you which one.
One REST Endpoint
Everything is a single endpoint: GET /v1/vat/{vatId}. The VAT number goes in the path, the result comes back as JSON. There is no separate “look up country,” “fetch company,” or “get rates” call to orchestrate — the country name, company identity, and that country’s VAT-rate metadata all come back in the same response.
Zero-Config: One Key, One Call
There is nothing to configure before your first successful request. Create a key, put it in an Authorization: Bearer header, and call the endpoint. No SOAP client library, no WSDL, no per-country setup.
curl https://api.vatnode.dev/v1/vat/IE6388047V \
-H "Authorization: Bearer vat_live_your_key_here"Endpoint and Authentication
- Path parameter
{vatId}— the full EU VAT identifier including the country prefix, e.g.IE6388047VorDE811257210. Whitespace and casing are normalized for you. - Authentication — a bearer token in the
Authorizationheader:Authorization: Bearer vat_live_your_key_here. Keys are per-environment;vat_live_…keys hit the live VIES path, test keys return fixtures.
Create a free key at Get a Free API Key — no credit card required — and read it from an environment variable in your code. Never hardcode a live key or ship it to the browser; all calls should run server-side. The quickstart and API authentication docs cover key management in full.
// Node 18+ / modern runtimes have global fetch
async function validateVat(vatId) {
const res = await fetch(`https://api.vatnode.dev/v1/vat/${encodeURIComponent(vatId)}`, {
headers: { Authorization: `Bearer ${process.env.VATNODE_API_KEY}` },
})
if (!res.ok) {
// 4xx/5xx — inspect the JSON error body; see /docs/errors
throw new Error(`vatnode ${res.status}: ${await res.text()}`)
}
const data = await res.json()
return {
valid: data.valid,
company: data.companyName,
address: data.companyAddress,
source: data.source,
checkId: data.checkId,
consultationNumber: data.consultationNumber,
}
}The Response Object
The response is a flat JSON object with a stable set of keys. Fields a member state doesn’t provide come back as null — they are never omitted.
{
"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",
"countryVatUpdatedAt": "2026-03-27"
}
}valid— the boolean verdict from the register.true/falseis a definitive answer; a transient upstream failure is an error, notvalid: false.companyName/companyAddress— trader identity as returned by the member state. Some states don’t disclose these; then they’renull.source— where the answer came from:"VIES"(live),"CACHE"(a recent cached base result), or a national registry code (e.g.BZST,MF_PL) when VIES was down and a national source answered.countryVat— that country’s current VAT-rate metadata, included so you don’t need a second lookup. It describes the country’s rates; it is not a tax determination for a specific transaction.checkIdandverifiedAt— the persistent identifier and UTC timestamp of this specific check.
Consultation Number and Audit Trail
By default the endpoint runs a plain valid/invalid check and returns consultationNumber: null. To get an EU-issued consultation number, supply your own VAT as requester. The simplest way is to set it once in the dashboard under Settings → Requester VAT — then every live call returns a consultation number with no extra parameters. If you’d rather set it per request (or override the account default), pass it as query parameters:
curl "https://api.vatnode.dev/v1/vat/IE6388047V?requesterCountryCode=IE&requesterVatNumber=6388047V" \
-H "Authorization: Bearer vat_live_your_key_here"Whether the requester comes from your account setting or the requesterCountryCode + requesterVatNumber query params (both or neither — query params override the account default), vatnode calls VIES’s checkVatApprox operation on your behalf, and the Commission issues a consultationNumber (VIES’s requestIdentifier) tied to your VAT number and the number you checked.
That consultation number is your audit evidence: it is proof, issued by the EU side, that you performed this specific validation at this time. Store it alongside checkId and verifiedAt next to the invoice or customer record it supports — see building a VAT audit trail. Whether a given VAT result justifies a particular tax treatment still depends on the transaction — supply type, place of supply, and other conditions — so treat these fields as evidence of validation, not as a tax determination.
Note: in requester-authenticated mode, national fallback is disabled — a consultation number can only come from VIES itself, so vatnode will not substitute a national source for that request. The full field-by-field contract is in the validation endpoint reference.
National Registry Fallback
When VIES is unavailable or times out, vatnode falls back to the national tax-authority or company-registry API for the number’s country, where such a source exists. You still get a validated result with the same response shape; the source field changes from "VIES" to the national system’s code so you always know which register answered. That lifts effective availability above raw VIES, where a single member-state outage would otherwise leave you with no answer. See the current registry coverage.
Fallback applies to the default (non-requester) check. In requester-authenticated mode it is disabled by design, because the consultation number must be issued by VIES and cannot be reproduced by a national source. If you need consultation numbers and maximum availability, decide per call which one matters more.
Errors, Timeouts and Retries
- Invalid format is rejected before any VIES call. If the VAT ID doesn’t match the country’s structural pattern, you get a definitive error immediately — no upstream round-trip.
- VIES unavailable — when VIES is unreachable and no national fallback applies, the API returns a VIES-unavailable error rather than a fabricated verdict. A transient upstream failure is cached briefly, so a number retried in a tight loop fast-fails instead of opening another slow VIES request.
Retry guidance: treat network errors and 5xx / VIES-unavailable responses as retryable with exponential backoff and a small attempt cap. Treat a definitive result — a valid/invalid verdict or an invalid-format rejection — as final. The full error-code list is at error codes.
async function validateWithRetry(vatId, attempts = 3) {
for (let i = 0; i < attempts; i++) {
const res = await fetch(`https://api.vatnode.dev/v1/vat/${encodeURIComponent(vatId)}`, {
headers: { Authorization: `Bearer ${process.env.VATNODE_API_KEY}` },
})
if (res.ok) return res.json()
// Definitive client errors (bad format, auth, quota) — do not retry.
if (res.status < 500) throw new Error(`vatnode ${res.status}: ${await res.text()}`)
// Transient upstream (5xx / VIES unavailable) — back off and retry.
await new Promise((r) => setTimeout(r, 2 ** i * 500))
}
throw new Error('vatnode: upstream unavailable after retries')
}Test Mode
Any VAT ID prefixed with XX returns a deterministic fixture instead of hitting VIES. Test-mode calls consume no quota and write nothing to the database, so they’re safe to run on every CI build and in local development. Use a test key and an XX number to exercise your integration end to end without touching the live register — details in test mode.
curl https://api.vatnode.dev/v1/vat/XX123456789 \
-H "Authorization: Bearer vat_test_your_key_here"Country Coverage
The VIES API covers the 27 EU member states plus XI (Northern Ireland), which VIES validates under the Northern Ireland Protocol. Numbers outside that scope are not supported. Browse the EU VAT API by country for per-country formats and examples, or check a single VAT number in the browser.
Pricing
The free plan requires no credit card and is enough to build and test a full integration. Paid plans start at €19/month for 1,000 requests, billed per call — you pay for validations, not seats or add-on modules. See API pricing for plan details.
Get a Free API Key
Free plan with no credit card. Validate EU VAT IDs via VIES with national-registry fallback, plus the official consultation number on checks where you supply your own VAT as requester.
Frequently Asked Questions
What is the VIES API?
It's a REST layer over the European Commission's VIES service that validates EU VAT identification numbers. Instead of building a SOAP client, you make one authenticated GET request and receive JSON with the valid/invalid verdict, the trader's company name and address, and VAT-rate metadata for that country. vatnode adds authentication, caching, a stable response contract, and national-registry fallback on top of VIES.
Does the official VIES service offer a REST API?
No. The Commission’s VIES service is SOAP-based: you exchange XML envelopes over HTTPS against a WSDL, with no API key and no structured JSON contract. vatnode wraps that SOAP service in a REST JSON API with bearer authentication, so you work with plain HTTP and JSON instead of building and maintaining a SOAP integration.
How do I get a VIES consultation number from the API?
Supply your own VAT as requester. The simplest way is to set it once in the dashboard under Settings → Requester VAT, and every live call then returns a consultationNumber with no extra parameters. You can also pass it per request as query parameters (?requesterCountryCode=IE&requesterVatNumber=6388047V), which override the account default. Either way vatnode calls VIES’s checkVatApprox operation and the Commission issues a consultationNumber tied to your number and the one you checked. With no requester at all you get a plain valid/invalid check and consultationNumber: null. Supplying a requester disables national fallback for that request, since the consultation number must come from VIES itself.
What happens when VIES is down or times out?
For a default check, vatnode falls back to the national tax-authority or company-registry API for that country where one is available, and sets the source field to that national system so you know which register answered. If no fallback applies, it returns a VIES-unavailable error instead of a fabricated verdict, and caches that transient failure briefly so retries fast-fail rather than hang. Treat those errors as retryable with backoff.
Which countries does the VIES API cover?
The 27 EU member states plus XI (Northern Ireland), which VIES validates under the Northern Ireland Protocol. Numbers outside that scope are not supported.
Is there a free VIES API tier?
Yes. The free plan requires no credit card and is enough to build and test a complete integration, including test-mode fixtures for CI. Paid plans start at €19/month for 1,000 requests when you need higher volume.
How is this different from calling VIES SOAP directly?
Calling VIES directly means writing a SOAP/XML client, handling per-member-state availability and downtime, and building your own caching and audit records — with no authentication or structured company-data contract. vatnode gives you one authenticated REST endpoint that returns a never-null JSON object, caches recent results, records each check with a checkId and timestamp, and falls back to national registries when VIES is unavailable. You still validate against the same authoritative EU register — vatnode just adds the production layer around it.