A VAT number can pass a regex and still be useless for an invoice: the trader is not in VIES, the ID belongs to another country, or the rate you applied has nothing to do with whether the number is valid. A VAT validation API has to answer two different questions — is this a registered VAT ID? and what tax applies to this transaction? — and keep them apart.
Try the checks in this guide
This is the canonical Cleariflow guide for EU VAT IDs and rates. The shorter posts linked at the end are implementation notes, not a second complete guide.
- Free browser tool: VAT check
- Production API: VAT Validation & Rates — VIES lookup plus tax-rate data for EU countries
- Start free — no credit card
- Endpoint reference: docs
Two questions at checkout
| Question | What you need | What a regex cannot do |
|---|---|---|
| Is this VAT ID registered? | VIES (or a national register) | Country prefix + checksum only prove shape |
| What rate applies? | Place of supply, buyer type, goods/services category | A valid ID does not imply 0% or reverse charge |
Treat those as two fields in your domain model. Mixing them is how “valid VAT number” becomes a wrong tax total.
What format checks are actually for
Format checks belong on the first keystroke and as a guard before you spend a VIES call:
- Country prefix (
DE,FR,SE, …) matches the address country you already collected. - Length and checksum match that country’s VAT syntax.
- Whitespace and punctuation are stripped once, then stored in a canonical form.
If the format fails, do not call VIES. If it passes, you still do not know whether the trader is registered today.
VIES: the registration check
VIES is the EU’s VAT Information Exchange System. A production validator should:
- Send the canonical VAT ID.
- Treat timeout / unavailable as a first-class state, not as
invalid. Finance teams still need to complete onboarding when VIES is down. - Persist the consultation evidence you are allowed to keep (request id, timestamp, valid flag, company name/address when returned) — not a screenshot of the public form.
- Never assume United Kingdom numbers behave like EU-27 VIES after Brexit. GB IDs need a separate policy.
Cleariflow’s VAT API validates through official VIES and returns company name/address when VIES provides them. It covers the 27 EU member states for that lookup. Do not advertise “worldwide VAT” from this endpoint.
Tax rates are a different API surface
Once you know who the buyer is, you still need how much tax to charge:
- Standard vs reduced vs super-reduced vs zero — by country and often by product category.
- Reverse charge for intra-EU B2B when the buyer’s VAT ID is valid and the place of supply rules say so.
- Historical rates if you reprint an invoice from last year.
A lookup that only returns valid: true cannot price a cart. Pair VIES with a rate table (Cleariflow exposes tax-rate calculation on the same product) and keep the decision log: which rate, which category, which date.
Where validation belongs in the product
Put the VIES call at the moment you have country + VAT ID + intent (B2B checkout, seller onboarding, invoice draft) — not on every keypress.
Recommended state machine:
| State | User-facing | System |
|---|---|---|
format_invalid |
Fix the number | No VIES |
vies_unavailable |
Continue, flag for review | Retry queue |
not_registered |
Ask for another ID or fall back to consumer VAT | Do not reverse-charge |
registered |
Show trader name if you have it | Safe to apply B2B rules if place-of-supply agrees |
Do not block checkout solely because VIES timed out. Do block reverse charge until registered.
Production API example
curl -sG "https://vat.cleariflow.com/v1/validate/" \
--data-urlencode "api_key=YOUR_API_KEY" \
--data-urlencode "vat_number=SE556656688001"
Typical payload includes valid, vat_number, company.name / company.address, and country.code. Use valid for registration; load rates in a separate step (or a dedicated rates call) before you freeze the invoice.
Product page: VAT Validation & Rates API. Docs: vat.
Evidence without over-collecting
Store what an auditor will ask for: canonical VAT ID, VIES result, time, and the rate snapshot you applied. Do not store full address dumps in application logs. Hash or truncate if you only need cache keys.
Conclusion
EU VAT in production is not “one checkbox.” Split registration (VIES) from rate (place of supply + category), degrade when VIES is down, and keep evidence.
Ship it:
Further reading
These are short notes on the same topic — not a second complete guide: