VIES VAT validation — what it checks, and how to do it properly
A VIES validation asks a national tax administration whether a VAT number is registered for intra-Community trade, and relays the answer. That is a narrower claim than most integrations assume, and the difference is where the expensive mistakes live. This page covers what the answer means, how to read the failure codes, and what to keep once you have it.
Free, no sign-up · all 27 EU member states via VIES, plus the United Kingdom and Norway
What a VIES validation is
VIES — the VAT Information Exchange System — is operated by the European Commission, and it holds no VAT data of its own. It is a router. You give it a country and a number; it forwards the question to the tax administration of that member state, waits, and relays whatever comes back. All 27 member states are reachable through the same interface, which is the entire point of it: one query shape instead of 27 national systems.
Because the answer comes from the issuing administration, it is current. And because VIES is a relay, everything that can go wrong between you and that administration shows up in the response — which is why reading the failure codes matters more here than in most APIs you will integrate.
What it does not tell you: whether the number belongs to the person who gave it to you, whether the company is solvent, or whether it is still trading. A valid VAT number is evidence about a registration, not about a counterparty.
A format check is not a validation
Every member state's VAT number follows a national pattern, and most carry a checksum. Austrian numbers are ATU followed by eight digits. Dutch numbers are twelve characters with a fixed B in position ten. You can test all of this offline, instantly, for free, and you should — but a well-formed number is not a registered one. A number that was cancelled last month still passes every format test it ever passed.
The two belong in that order. Check the format locally to catch typos, then send what survives to VIES. This is what our own API does, and it is not only about speed: a malformed number sent to a member state comes back as INVALID_INPUT, which reads like a verdict on the number and is really a complaint about the request.
What VIES gives you back
A successful validation is a small object. These are the fields that matter, named as TaxID reports them:
| valid | Whether the member state recognises the number as registered right now. |
| country_code | The member state that issued it — the two letters at the front of the number. |
| vat_number | The number as validated, normalised: no spaces, no punctuation, no duplicated prefix. |
| company_name | The registered name, where the member state publishes it. Germany and Spain usually withhold it. |
| company_address | The registered address, on the same terms. |
| request_date | When the answer was produced. This is the timestamp your evidence hangs on. |
Name and address are optional at the member state's discretion. Germany and Spain routinely withhold both, and a null name alongside valid: true is a complete, correct answer — not a degraded one.
The four answers, and what each is worth
VIES has a large vocabulary of response codes, but they collapse into four situations. Integrations that branch on a boolean instead of a status conflate the last two with the second, and that is the bug that costs customers.
The number is registered
VALIDThe issuing member state recognises the number today.
What to do: Proceed. Record the number, the timestamp and the response.
The number is not registered
INVALIDThe member state answered, and the answer is no. Either the number was never issued, or the registration has ended.
What to do: Do not zero-rate. Go back to the customer — in practice this is often a transcription error rather than a fake number.
Nobody answered
MS_UNAVAILABLE · SERVICE_UNAVAILABLE · TIMEOUTThe member state's system, or the central VIES component, did not reply. There is no verdict on the number at all.
What to do: Retry later. Never fall back to treating the number as invalid — that turns someone else's outage into a lost customer.
The queue was full
MS_MAX_CONCURRENT_REQ · GLOBAL_MAX_CONCURRENT_REQ · SERVER_BUSYA shared concurrency limit was hit. Not your quota, and not evidence that the member state is unhealthy.
What to do: Retry with exponential backoff. Do not treat it as downtime in your own monitoring.
The concurrency limits deserve their own warning. They are a queue shared by every VIES caller in Europe, not a quota assigned to you, so you can hit one on the first request you make all day. Counting them as downtime makes healthy member states look permanently broken; counting them as success flatters everyone. We exclude them from our own uptime figures for exactly that reason.
What to keep as evidence
If the validation exists to support zero-rating an intra-Community supply, the check is not the deliverable — the record of it is. Since the 2020 quick fixes, the customer's valid VAT identification number is a substantive condition of the exemption under Article 138 of the VAT Directive rather than a formality, which means you may be asked to show what you checked and when.
At minimum, keep the number exactly as validated, the timestamp of the response, and the response itself. Storing the normalised form matters more than it sounds: if you record what the customer typed and revalidate what you normalised, the two drift and your audit trail stops matching your invoices.
One thing worth knowing before your adviser asks for it: VIES issues a consultation numberonly when the caller identifies itself, supplying its own member state and VAT number alongside the query. A validation made anonymously — which includes the one this site performs — returns no consultation number. TaxID gives you a request identifier and a timestamp for your own trail; if your administration specifically requires the Commission's consultation number, run that check yourself through the VIES web portal with your own VAT number as requester.
This is a description of how the system works, not tax advice. What satisfies your own tax administration is a question for your adviser.
Five mistakes that account for most wrong answers
- 01
Sending the country prefix twice
The VIES call takes the country and the number separately. Customers write theirs as DE123456789, so DE plus DE123456789 is what a naive integration sends, and the member state answers INVALID_INPUT — which is not the same as the number being invalid. Strip the prefix from the number before you send it. In our own traffic this is the most common cause of a wrong answer.
- 02
Passing spaces and punctuation through
Invoices carry numbers as FR 12 345678901 or ATU 1234 5678. Whitespace and separators are formatting, not data. Normalise to uppercase alphanumerics before validating, and store the normalised form so a second check months later produces the same key.
- 03
Treating an outage as a rejection
The error paths from a real member state outage and a genuinely invalid number look similar if you only check for a truthy `valid` flag. They are opposites. Branch on the status, not on the boolean.
- 04
Validating at the wrong moment
Validating only at signup means a number that lapses two years later is still on your invoices. Validating on every request means a member state outage takes your checkout down with it. The workable shape is: validate at signup, cache the result, revalidate on a schedule and before the invoice that depends on it.
- 05
Assuming the name will come back
Several member states — Germany and Spain among them — do not publish the registered name and address through VIES. A `valid` answer with a null name is normal, not a partial failure, and an integration that requires the name to proceed will reject real customers in exactly those countries.
When the free checker is enough
Most people arriving at this question need to check a number, not build something. If that is you, the free VAT number checker runs the same query against the same member state, shows you the raw response, and asks for nothing. It covers all 27 EU member states via VIES, plus the United Kingdom and Norway.
You have outgrown it the moment the check has to happen without a person watching: a checkout deciding whether to charge VAT, a nightly revalidation sweep, an ERP that blocks an invoice until the number clears. That is a question of where the check sits, not how many you do — a hundred manual checks a month are still manual, and one automated check a week still needs an API.
If that is where you are, the VIES API reference covers the integration: REST instead of SOAP, caching, and the status codes that keep an outage from looking like a rejection.
Frequently asked questions
What does a VIES validation actually prove?
That at the moment you asked, the tax administration of the member state that issued the number recognised it as registered for intra-Community trade. It is a live answer from the national register, not a lookup in a copy of it. It does not prove the number belongs to the person quoting it at you, and it does not prove the company is solvent or trading.
What is the difference between a VIES check and a format check?
A format check tests the number against the national pattern and checksum — ATU plus eight digits for Austria, eleven digits for the Netherlands, and so on. It is instant, free and offline, and it catches typos. It cannot tell you whether the number was ever issued or is still active. A VIES check asks the issuing member state. The two are complementary: check the format first so you do not spend a live lookup on a typo.
What does MS_UNAVAILABLE mean?
The member state's own system did not answer. VIES is a router: it forwards your query to the national tax administration and relays the reply. When that administration is down or unreachable, VIES has nothing to relay and says so. It is not a verdict on the number. Treat it as "ask again later", never as "invalid" — rejecting a customer on MS_UNAVAILABLE is the single most expensive mistake in a VAT integration.
Why do I get a concurrency error when I have sent almost no traffic?
The concurrency limits — MS_MAX_CONCURRENT_REQ and its global counterpart — are a queue in front of each member state that every VIES caller in Europe shares. They are not a per-caller quota, so you can hit one on your first request of the day. Like MS_UNAVAILABLE it says nothing about the number and nothing about whether the member state is healthy. Retry with backoff.
Do I need to keep evidence of the check?
If you are zero-rating an intra-Community supply, yes. Since the 2020 quick fixes, the customer's valid VAT identification number is a substantive condition of the exemption under Article 138 of the VAT Directive, not merely a formality — so you need to be able to show what you checked, when, and what came back. Keep the number as validated, the timestamp, and the response. This is not tax advice; how much evidence satisfies your own administration is a question for your adviser.
When is the free checker enough, and when do I need the API?
The free checker is enough when a person is validating a handful of numbers — onboarding a new supplier, checking an invoice before it goes out. You need the API when the check has to happen inside a process: a checkout that decides whether to charge VAT, a nightly revalidation of your customer base, an ERP that will not let an invoice through without it. The dividing line is whether a human is present, not the volume.
Put VIES validation inside your product
One REST call, cached answers in under 10ms, and a distinct status for “nobody answered” so an outage in one member state never reads as an invalid customer. Free plan: 100 validations a month, no card.