EU VAT Number Validator (VIES) - Bulk Check, No Login
Pricing
from $1.60 / 1,000 vat number checkeds
EU VAT Number Validator (VIES) - Bulk Check, No Login
Bulk-validate EU VAT numbers against the official EU VIES service: valid or invalid, company name and address, consultation number. Member-state outages are reported as unavailable, never as invalid.
Pricing
from $1.60 / 1,000 vat number checkeds
Rating
0.0
(0)
Developer
Cliqto Media
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
11 days ago
Last modified
Categories
Share
Check a list of EU VAT numbers against the European Commission's VIES service and get one row per number: valid or invalid, the registered company name and address when the country shares them, and an honest status when a country's database is down. No login, no API key.
Paste up to 1,000 VAT numbers with their country prefix (for example IE6388047V) and click Start. A run of 6 numbers takes a few seconds and costs about $0.01.

Table of contents
- What it does
- Quick start
- Input
- Output
- Pricing and limits
- Use cases
- API, export and integrations
- Troubleshooting
- FAQ
- Support
What it does
VIES (VAT Information Exchange System) is the European Commission service that asks each EU country's tax database whether a VAT number is registered for cross-border trade. This Actor sends your numbers to the public VIES REST API one by one and saves the answer for each number in a dataset.
Before a number goes to VIES, the Actor cleans it (spaces, dots and dashes are removed, GR becomes EL) and checks the country's number format. Numbers with a wrong format are reported as format_error and are never sent.
The main difference from a simple VIES call: a VIES "no answer" is not turned into "invalid". When a country is busy or down (VIES codes MS_MAX_CONCURRENT_REQ and MS_UNAVAILABLE), the Actor waits and asks again. If the country still does not answer, the row gets status: "service_unavailable" and valid: null, not valid: false.
Good fit
- Check customer VAT numbers before you send an invoice without VAT (EU reverse charge).
- Clean a CRM or lead list: mark invalid numbers and fill in the registered company name.
- Re-check a supplier list and keep the VIES consultation number as proof of the check.
Not a fit / limits
- UK (GB) numbers are not checked. They left VIES in 2021, and the UK HMRC API needs registered API credentials. They get
status: "unsupported_country". Northern Ireland traders (XIprefix) are checked through VIES. - Non-EU numbers (Norway, Switzerland, US and others) get
unsupported_country. - You cannot search by company name. VIES only checks a number.
- Some countries (for example Germany and Spain) do not share the name and address. Then
nameandaddressarenulleven when the number is valid. - This is a one-time check of a list. There is no monitoring mode and no history.
Quick start
- Open the Input tab.
- Add your numbers to VAT numbers (
vatNumbers), one per line, with the two-letter country prefix. The form is prefilled with 5 public company numbers and one number with a wrong format (DE12). - Optional: add your own EU VAT number in
requesterVatto get a consultation number for each valid check. - Click Start.
- Open the Output tab. The Results view shows
status,valid,nameandaddressfor each number.
Expected result for the prefill: 5 rows with status: "valid" (with company names, except the German number: Germany does not share names in VIES), and 1 row with status: "format_error" for DE12.
Input
Input fields
| Field | Plain name | Type | Required | Default / prefill | Allowed values | Effect | Example | Recommendation |
|---|---|---|---|---|---|---|---|---|
vatNumbers | VAT numbers | array of strings | yes | no default; prefill of 6 numbers | 1–1,000 items, each with an EU country prefix | Numbers to check | ["IE6388047V", "de 143.454.214"] | Keep the country prefix. Spaces, dots and dashes are fine. |
requesterVat | Your own EU VAT number | string | no | empty | one EU VAT number with prefix | VIES returns a consultationNumber for each valid check | "IE6388047V" | Use it when you need proof that you checked a customer. |
retryUnavailable | Retry unavailable countries | boolean | no | true | true / false | When a country is down, retry it up to 3 more times (waits of 15, 30 and 60 seconds) | true | Turn off only if you need the fastest possible answer. |
How the input is read:
- Each number is cleaned: upper case, spaces, dots, dashes and similar marks removed, full-width digits changed to normal digits.
GRis changed toEL(the VIES code for Greece). - Duplicates (after cleaning) are checked once. The result row shows how many extra copies there were in
duplicateInputs. - Empty input or more than 1,000 numbers: the run fails at once with a clear message and nothing is charged except the start fee.
- An invalid
requesterVatformat fails the run with a clear message. If VIES rejects a well-formedrequesterVat, the Actor logs a warning and checks your numbers without it.
Interacting settings
| When | Input A | Input B | Effective behavior | Cost/result effect |
|---|---|---|---|---|
| A country is down | vatNumbers | retryUnavailable: true | Numbers of that country are retried in up to 3 rounds (about 2 minutes extra) | Longer run; service_unavailable rows have no check fee |
| A country is down | vatNumbers | retryUnavailable: false | No retry rounds: numbers of that country are reported as service_unavailable right away (short busy retries of 2 and 5 seconds still happen) | Faster run |
| You need proof | vatNumbers | requesterVat | Each valid row gets a consultationNumber from VIES | Same price |
Input example
{"vatNumbers": ["IE6388047V", "LU20260743", "NL810433941B01", "DE143454214", "ATU33803701", "DE12"],"retryUnavailable": true}
Expected behavior: 5 numbers are sent to VIES, DE12 is stopped by the format check.
Expected output: 6 rows; 5 valid with names where the country shares them, 1 format_error.
Cost: about $0.0103 (5 checks + 6 rows + start fee, see Pricing).
Output
Each unique input number gives one dataset row. A run summary is saved in the key-value store as RUN_SUMMARY.
Output example
One valid row and one format_error row from a real run:
[{"input": "IE6388047V","countryCode": "IE","vatNumber": "6388047V","fullVatNumber": "IE6388047V","status": "valid","valid": true,"name": "GOOGLE IRELAND LIMITED","address": "3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4","requestDate": "2026-10-13T16:13:43.268Z","consultationNumber": null,"errorCode": null,"errorMessage": null,"attempts": 1,"duplicateInputs": 0,"source": "EU VIES (European Commission)","sourceUrl": "https://ec.europa.eu/taxation_customs/vies/","checkedAt": "2026-10-13T16:13:43.314Z"},{"input": "DE12","countryCode": "DE","vatNumber": "12","fullVatNumber": "DE12","status": "format_error","valid": null,"name": null,"address": null,"requestDate": null,"consultationNumber": null,"errorCode": "FORMAT_ERROR","errorMessage": "Does not match the DE VAT number format.","attempts": 0,"duplicateInputs": 0,"source": "EU VIES (European Commission)","sourceUrl": "https://ec.europa.eu/taxation_customs/vies/","checkedAt": "2026-10-13T16:13:42.494Z"}]
consultationNumber is null here because the run had no requesterVat.
Output fields
| Field | Meaning | Type | Can be empty? | Example / enum |
|---|---|---|---|---|
input | The number exactly as you typed it | string | no | de 143.454.214 |
countryCode | VIES country code (EL = Greece, XI = Northern Ireland) | string | null when no prefix was found | DE |
vatNumber | Number without prefix and separators | string | null when no prefix was found | 143454214 |
fullVatNumber | Cleaned number with prefix | string | null when no prefix was found | DE143454214 |
status | Result of the check | string | no | valid, invalid, service_unavailable, format_error, unsupported_country, not_checked, error |
valid | VIES verdict | boolean | null when VIES gave no verdict | true |
name | Registered trader name | string | null when the country does not share it | GOOGLE IRELAND LIMITED |
address | Registered address on one line | string | null when not shared | 3RD FLOOR, GORDON HOUSE, … |
requestDate | Time of the VIES answer | string (ISO 8601) | null when VIES was not asked or did not answer | 2026-10-13T16:13:43.268Z |
consultationNumber | Official VIES consultation number | string | null without requesterVat | WAPI… |
errorCode | Why there is no verdict | string | null for valid / invalid | MS_UNAVAILABLE, FORMAT_ERROR, UNSUPPORTED_COUNTRY, CHARGE_LIMIT |
errorMessage | The same in plain words | string | null for valid / invalid | Does not match the DE VAT number format. |
attempts | Requests sent to VIES for this number | integer | no | 1 |
duplicateInputs | Extra copies of this number in your input | integer | no | 0 |
source / sourceUrl | Where the answer came from | string | no | EU VIES (European Commission) |
checkedAt | When this row was made | string (ISO 8601) | no | 2026-10-13T16:13:43.314Z |
What each status means:
status | valid | Meaning | What to do |
|---|---|---|---|
valid | true | VIES says the number is active for cross-border trade | Use it |
invalid | false | VIES says the number is not registered or not active | Ask the customer to check the number |
service_unavailable | null | The country's database did not answer, even after retries. This is not invalid. | Run these numbers again later |
format_error | null | The number does not match the country's format; it was not sent to VIES | Fix the number |
unsupported_country | null | Prefix is not an EU VIES country (for example GB, NO, CH) | Check it with that country's own service |
not_checked | null | The run stopped before this number (time limit, your charge limit, or VIES stopped answering) | Run these numbers again |
error | null | VIES returned an unexpected error for this number | Run it again later |
Output views and run summary
| Situation | Where to look | What you see |
|---|---|---|
| Normal run | Dataset view Results | All rows with status, name, address, consultation number |
| Status and error codes | Dataset view Status and errors (all rows; sort or filter by status when exporting) | Input, status, error code, note, attempts |
| Every input has a wrong format | Dataset | Only format_error rows; run is SUCCEEDED |
| A country was down | Dataset + RUN_SUMMARY | service_unavailable rows; unavailableCountries lists the countries; run is SUCCEEDED |
| Run stopped early | RUN_SUMMARY | status: "PARTIAL" with reason: CHARGE_LIMIT or DEADLINE_REACHED (remaining rows are not_checked), VIES_NOT_RESPONDING (VIES gave no verdict for 2 minutes; remaining rows are service_unavailable or not_checked), MEMBER_STATE_UNAVAILABLE (some rows are service_unavailable) |
| Bad input or VIES fails many times in a row | Run status + RUN_SUMMARY | Run FAILED with a clear message; rows saved before the stop stay in the dataset |
RUN_SUMMARY contains status, reason, message, counts per status, charged, duplicatesMerged, unavailableCountries, request statistics and timing.
Pricing and limits
Pricing unit
This Actor uses pay-per-event pricing. You pay for:
| Event | When | Price |
|---|---|---|
| Actor start | Once per run (at the default 256 MB memory) | $0.0007 |
| VAT check | Each number that gets a VIES verdict (valid or invalid) | $0.0019 (Free plan), $0.0018 (Bronze), $0.0017 (Silver), $0.0016 (Gold and higher) |
| Result row | Each row saved to the dataset, for any status | $0.00002 |
Numbers with service_unavailable, format_error, unsupported_country, not_checked or error have no VAT check fee. They only cost the $0.00002 row fee. Duplicates are checked and charged once.
Platform usage (compute, storage) is included in the event prices.
Cost examples (Free plan prices)
| Scenario | Input | Events | Total |
|---|---|---|---|
| Prefill | 6 numbers, 5 verdicts | 1 start + 5 checks + 6 rows | $0.0103 |
| Small | 10 numbers, all with verdicts | 1 start + 10 checks + 10 rows | $0.0199 |
| Normal | 100 numbers, all with verdicts | 1 start + 100 checks + 100 rows | $0.1927 |
| Maximum | 1,000 numbers, all with verdicts | 1 start + 1,000 checks + 1,000 rows | $1.9207 |
| Only wrong formats | 1,000 numbers, all format_error | 1 start + 1,000 rows | $0.0207 |
Your maximum total charge for a run (set in the run options) is respected. When the next check would go over it, the Actor stops sending numbers, marks the rest as not_checked (no check fee) and ends the run as SUCCEEDED with reason: "CHARGE_LIMIT".
Limits and speed
- Up to 1,000 numbers per run. Split bigger lists into several runs.
- Speed: about 100 numbers per minute when the list has many countries (1,000 numbers from 12 countries took about 4.5 minutes in our test). The Actor sends only one request at a time to each country, because VIES limits parallel requests per country. So a list from one country is slower: 194 German numbers took about 1.5 minutes in our test. A very long list from one slow country may not finish within the 900-second timeout; the rest is then marked
not_checked(no check fee) — split such lists or raise the timeout. - Default run options: 256 MB memory, 900-second timeout. More memory does not make the run faster.
- If the run time limit is close, the Actor stops sending numbers 20 seconds before it and marks the rest as
not_checked. - If VIES gives no verdict at all for 2 minutes (only "busy" or "unavailable" answers), the Actor stops early with
reason: "VIES_NOT_RESPONDING"instead of waiting until the timeout. Run the list again later.
Use cases
| Buyer job | Input | Key fields | Next step |
|---|---|---|---|
| Check a customer before a reverse-charge invoice | vatNumbers + requesterVat | status, valid, consultationNumber, requestDate | Save the consultation number with the invoice |
| Clean a CRM or lead list | vatNumbers (export from CRM) | status, name, address | Export CSV and update the CRM |
| Re-check suppliers every month | vatNumbers in a saved task | status, errorCode | Schedule the task; follow up on invalid rows |
API, export and integrations
- API: start a run with
POST https://api.apify.com/v2/acts/cliqtomedia~vat-number-validator/runsand the input JSON above. Read rows from the run's default dataset. - Export: download the dataset as JSON, CSV, Excel or XML from the Output tab or the dataset API.
- Scheduling: save your input as a task and add an Apify schedule to re-check the same list.
- Webhooks / no-code: use an Apify integration (Make, Zapier, webhooks) to send the rows on when the run finishes. Filter on
statusin the next step.
Use with AI agents (MCP)
- MCP server URL with only this Actor:
https://mcp.apify.com?tools=cliqtomedia/vat-number-validator - Smallest useful input:
{"vatNumbers": ["IE6388047V"]} - Key output fields:
fullVatNumber(cleaned number),status(see the status table),valid(true / false / null),nameandaddress(null when the country does not share them). - The 6-number prefill finished in 2–8 seconds in our tests and costs about $0.01; 100 numbers take about 1 minute and cost about $0.19. Maximum 1,000 numbers per run.
valid: nullnever means invalid. ReadstatusanderrorMessagefor the reason.
Troubleshooting
Many numbers show service_unavailable
Symptom: rows from one country have status: "service_unavailable" and errorCode: "MS_UNAVAILABLE" or "MS_MAX_CONCURRENT_REQ".
Likely reason: that country's tax database was down or busy. This happens on the VIES side, often for a short time.
Check: RUN_SUMMARY → unavailableCountries. The VIES website shows which countries are available now.
Action: run only these numbers again later. Keep retryUnavailable: true.
A number I know is real shows format_error
Symptom: errorMessage says the number does not match the country's format.
Likely reason: a missing or wrong country prefix, a missing digit, or extra text in the cell (for example a company name or HTML).
Check: compare input with the country's VAT format; the prefix must be the VIES code (EL or GR for Greece, XI for Northern Ireland).
Action: fix the number and run it again.
A valid number has no name or address
Symptom: status: "valid" but name and address are null.
Likely reason: some countries (for example Germany and Spain) do not share these details through VIES.
Action: nothing is wrong. The verdict is still valid.
The run ended with some not_checked rows
Symptom: RUN_SUMMARY.status is PARTIAL and some rows are not_checked.
Likely reason: your maximum total charge or the run timeout was reached.
Action: raise the maximum charge or the timeout, or run the not_checked numbers in a new run.
The run failed at once
Symptom: run status FAILED with "Invalid input".
Likely reason: vatNumbers is empty, has more than 1,000 items, or requesterVat has a wrong format.
Action: fix the input as the message says.
FAQ
Do I need a login or an API key?
No. VIES is a public service of the European Commission. You only need an Apify account to run the Actor.
Can I check UK VAT numbers?
Not GB numbers: they left VIES in 2021, and the UK HMRC check needs registered API credentials. Northern Ireland numbers with the XI prefix are checked through VIES.
Is a service_unavailable number invalid?
No. It means the country did not answer. Run it again later. You do not pay the check fee for it.
How fresh is the data?
Each check is a live VIES request at run time. requestDate shows the time of the VIES answer. The Actor does not cache results.
Is the result legal proof?
When you add your own VAT number in requesterVat, VIES returns a consultation number. It is the VIES record that you checked this number on that date. Whether it is enough proof for your tax office is a question for your tax adviser.
Support
For bugs, questions or feature requests, open an issue in the Issues tab of this Actor. Include the run ID and the numbers that gave an unexpected result. Do not send API tokens or private customer data.