EU VAT Number Validator & KYB Checker
Pricing
from $10.00 / 1,000 vat number checks
EU VAT Number Validator & KYB Checker
Bulk-validate EU VAT numbers against the official VIES service. Offline checksum pre-filtering, member-state outage detection, consultation numbers for audit evidence, and company-name matching.
Pricing
from $10.00 / 1,000 vat number checks
Rating
0.0
(0)
Developer
J Act2Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Bulk EU VAT number validation against the official VIES service, built for finance and compliance teams who need answers they can defend in an audit. The offline checksum layer is differential-tested against python-stdnum across 568,173 generated numbers, with zero false rejections and zero false acceptances — so a number this Actor rejects without spending an API call really is impossible. Paste a list of VAT numbers or upload customer records, and get back validity, the registered company name and address, a name-match score, and the VIES consultation number that proves you performed the check. Covers all 27 EU member states plus Northern Ireland, with offline checksum validation for Great Britain.
What this VAT validation API does differently
Most VAT checkers make the same mistake: when a national tax database is offline, they report the VAT number as invalid. That is not a cosmetic bug. Acting on it means charging VAT to a legitimate B2B customer, or zero-rating a sale you should have taxed. Both are expensive to unwind.
This Actor never conflates the two. Every result is one of five explicit states:
| Status | Meaning |
|---|---|
valid | Registered and active in VIES |
invalid | VIES confirms the number is not registered |
unverifiable | No authoritative answer — member state offline, timeout, or throttled. Not the same as invalid, and never charged. |
malformed | Failed its country's official checksum. Rejected locally, no API call spent. |
not_supported | Outside VIES coverage (Great Britain since Brexit) |
The valid field is true, false, or null. It is only ever null when we genuinely do not know.
Features
- ✅ All 27 EU member states + XI (Northern Ireland), with
GRaccepted as an alias forEL - 🔍 Offline checksum pre-filtering for 29 jurisdictions — typos are caught before an API call is spent, so you are not billed for them
- 🛡️ Member-state outage detection via the VIES status endpoint, so an outage is never reported as an invalid number
- 📜 Consultation numbers (
requestIdentifier) captured as audit evidence under Article 31 of Regulation 904/2010 — this cannot be obtained retroactively - 🏢 Company-name matching for KYB, tolerant of legal-form differences (
GmbHvsGesellschaft mit beschränkter Haftung), diacritics, punctuation, word order and typos - 🔁 Correct throttling behaviour — VIES limits by concurrency, not requests per second, so calls to a single member state are serialised and transient errors are retried with exponential backoff
- 🧠 Automatic de-duplication — the same VAT number twice in one run costs one API call and one charge
- 🚦 Fails safe on
IP_BLOCKED— aborts rather than hammering VIES and getting your address blocked for longer
What data you get back
| Field | Description |
|---|---|
normalisedVatId | Country code + number, uppercase, no separators. Safe as a database key. |
status / valid | See the table above |
formatCheck | pass, fail, or unknown (a possible national personal-ID variant, sent to VIES rather than rejected) |
companyName / companyAddress | As held by the member state. null where the state withholds it — Germany and Spain always do. |
nameMatch / nameMatchScore | match / partial / mismatch, plus a 0–1 score |
consultationNumber | VIES proof-of-check identifier |
checkedAt | VIES requestDate where available |
reference | Your own row identifier, passed through unchanged |
message | Plain-language explanation whenever the result needs one |
How to validate EU VAT numbers with this Actor
- Simple list — paste VAT numbers into the VAT numbers field, one per line. Prefixes and spacing are optional:
DE136695976,FR 40 303.265-045andie6388047vare all accepted. - KYB mode — use the Records field instead, with objects containing
vatNumber,expectedNameandreference, to also verify the registered name matches your records. - Audit mode — fill in Your own VAT number to receive a consultation number with every result.
- Run it, then take the results from the dataset as JSON, CSV or Excel, or via the API.
Pricing
Pay per event. You are charged for:
- A verified answer — VIES confirmed the number as valid or invalid
- An offline rejection — a number that failed its country's official checksum, billed at a fraction of the verified rate because no API call was made
You are not charged for rows we could not verify (member-state outage, timeout, throttling), or for input outside VIES coverage. Duplicate numbers within a run are charged once.
Input example
{"records": [{ "vatNumber": "IE6388047V", "expectedName": "Google Ireland Limited", "reference": "CUST-1001" },{ "vatNumber": "LU26375245", "expectedName": "Amazon Europe Core", "reference": "CUST-1002" }],"requesterVatNumber": "DE123456789","maxConcurrency": 4}
Output example
{"input": "IE6388047V","reference": "CUST-1001","countryCode": "IE","vatNumber": "6388047V","normalisedVatId": "IE6388047V","status": "valid","valid": true,"formatCheck": "pass","companyName": "GOOGLE IRELAND LIMITED","companyAddress": "3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4","expectedName": "Google Ireland Limited","nameMatch": "match","nameMatchScore": 1,"consultationNumber": "WAPIAAAAWuJShAAA","checkedAt": "2026-08-12T11:33:23.919Z","source": "vies","message": null}
A German number, by contrast, comes back valid with no name, because Germany withholds it:
{"normalisedVatId": "DE123456789","status": "valid","valid": true,"companyName": null,"companyAddress": null,"nameMatch": null,"message": "DE does not disclose the registered name and address through VIES for data-protection reasons."}
VIES error codes, and why none of them means "invalid"
Every error below arrives from VIES with HTTP status 200 — not the 400 that the official documentation and three independent SDKs all describe. The body looks like this:
{ "actionSucceed": false, "errorWrappers": [{ "error": "MS_MAX_CONCURRENT_REQ" }] }
Note what is missing: there is no valid field. A client written the obvious way — if (response.ok) { /* treat as a successful lookup */ } — accepts every one of these as success, finds no valid field, and degrades the row to "not registered". That is the bug that makes VAT validators report live VAT numbers as invalid whenever VIES is busy.
This Actor reads the error code before it trusts any validity flag. A row is reported valid or invalid only when VIES returned no error code at all.
The official VIES test service documents 13 trigger values. Two of them (100 and 200) are the valid and not-registered happy paths; the other 11 are error codes, and every one of them was captured from the live service and replayed through the real client in this Actor's test suite:
| Trigger | VIES error | What it actually means | What this Actor does |
|---|---|---|---|
300 | SERVICE_UNAVAILABLE | VIES itself is unavailable | Retry with exponential backoff, then unverifiable |
301 | MS_UNAVAILABLE | The member state's own database is not responding | Retry, then unverifiable |
302 | TIMEOUT | The member state did not answer in time | Retry, then unverifiable |
600 | MS_MAX_CONCURRENT_REQ | Too many requests open against one member state | Retry, then unverifiable |
601 | MS_MAX_CONCURRENT_REQ_TIME | The same limit, expressed over a time window | Retry, then unverifiable |
500 | GLOBAL_MAX_CONCURRENT_REQ | A VIES-wide concurrency limit, not yours specifically | Retry, then unverifiable |
501 | GLOBAL_MAX_CONCURRENT_REQ_TIME | The same global limit, over a time window | Retry, then unverifiable |
201 | INVALID_INPUT | VIES rejected the country code or number shape | unverifiable, with the reason on the row |
202 | INVALID_REQUESTER_INFO | The requester VAT number you supplied is not usable | unverifiable, and the log tells you how to fix it |
400 | VAT_BLOCKED | VIES has blocked lookups for that one number | unverifiable, with the reason on the row |
401 | IP_BLOCKED | VIES has blocked your IP address | Aborts the whole run rather than making it worse |
Not one of them produces invalid. That behaviour is pinned by the test suite rather than assumed, so it cannot regress silently.
What MS_MAX_CONCURRENT_REQ and GLOBAL_MAX_CONCURRENT_REQ really mean
These are the two you will meet most often, and neither means you sent too many requests per second. VIES limits by concurrency, not by rate. Sequential requests a second apart still hit MS_MAX_CONCURRENT_REQ when the member state is already busy with other people's traffic — France does it routinely, from different IP addresses on different days. Raising your delay between requests will not help; reducing how many you have open at once will. So calls to a single member state are serialised here, while different member states run in parallel, and transient concurrency errors are retried with exponential backoff. A row that stays throttled through every retry is reported unverifiable and is not charged.
INVALID_REQUESTER_INFO when your own VAT number looks fine
The requester must be an EU member-state VAT number, or a Northern Ireland (XI) one. Great Britain left VIES, so a GB number will not work however valid it is — and a 10-digit UK number is a Unique Taxpayer Reference, a different identifier from a VAT registration number altogether. Supply an unusable requester and VIES answers INVALID_REQUESTER_INFO on every row, which quietly ruins the whole run. This Actor checks the shape before it starts, warns you in the log, and carries on without the requester rather than failing every lookup.
IP_BLOCKED and VAT_BLOCKED are not the same problem
VAT_BLOCKED is scoped to a single number: that row comes back unverifiable with the reason attached, and the run continues normally. IP_BLOCKED is scoped to you, and retrying extends it, so the run aborts immediately with an explanation instead of digging the hole deeper. If you hit it: lower the concurrency, cache results on your side, and contact TAXUD if it persists.
FAQ
Why is companyName empty for a valid German or Spanish VAT number?
Those member states do not disclose the registered name and address through VIES, for data-protection reasons. VIES returns ---, which this Actor reports as null with an explanatory message rather than pretending the name is missing or mismatched.
What is a consultation number and why should I store it? It is the identifier VIES returns as evidence that you verified a counterparty on a specific date, relevant under Article 31 of Regulation 904/2010. VIES only issues it when you supply your own VAT number in the request, and it cannot be recovered later. If VAT compliance is the reason you are running this, fill in Your own VAT number and keep the output. The run summary reports how many consultation numbers came back, and the log warns you if you asked for them and got none — so you find out immediately, rather than during an audit.
Does the name-match verdict come from VIES?
No. VIES accepts a trader name for comparison, but member states frequently return NOT_PROCESSED rather than a verdict — Ireland does so even when the name supplied is character-for-character correct. So nameMatch and nameMatchScore are computed here, against the registered name VIES returns, after normalising legal-form suffixes, diacritics, punctuation and word order. VIES's own verdict is used only when a member state actually provides one.
Can I use my UK company's tax number to get consultation numbers?
No, for two separate reasons. First, a 10-digit number is a Unique Taxpayer Reference (UTR), which is a different identifier from a VAT registration number (9 or 12 digits). Second, even a genuine Great Britain VAT number will not work, because GB left VIES — the requester must be an EU member-state VAT number, or a Northern Ireland (XI) one. If you supply something unusable the Actor says so in the log and carries on without it, rather than letting VIES reject every row.
How many numbers can I check in one run? There is no hard cap, but VIES throttles by concurrency and will block an IP that pushes too hard. The defaults are deliberately conservative. For large recurring lists, cache results on your side and re-check on a schedule rather than re-validating the same numbers repeatedly.
Can it check UK VAT numbers?
Great Britain left VIES after Brexit, so live GB lookups require the HMRC Check a UK VAT Number API, which needs your own OAuth credentials (the open v1 endpoint was withdrawn in February 2025). GB numbers are format- and checksum-validated offline and returned as not_supported rather than being wrongly marked invalid. Northern Ireland (XI) is in VIES and is fully supported.
Does a malformed result mean the number is definitely fake?
It means the number does not satisfy the published format and check digit for that country. A handful of countries allow a national personal identification number to be used as a VAT number, and those branches are poorly documented, so anything ambiguous is marked formatCheck: "unknown" and sent to VIES for the real answer instead of being rejected.
Is this an official EU service? No. It queries the official European Commission VIES service on your behalf. The Commission obtains data from national databases and does not guarantee its accuracy.
Notes on data protection
VIES is a register of taxable persons, not a consumer database. It is not, however, strictly company-only: several member states (Bulgaria, Czechia, Latvia, Lithuania, Romania, Slovakia) issue VAT numbers to sole traders, and in some of those the number encodes a national personal identification code that embeds a date of birth. Treat stored VAT numbers from those jurisdictions as potentially personal data under the GDPR, and take your own advice on retention.
Support
Open an issue on the Actor's Issues tab. Bug reports with the input that triggered them get fixed fastest.