0101 Introduction
A VAT number is the field that decides how a cross-border B2B invoice is taxed. Get it wrong and you can end up owing the VAT you never charged.
Most teams collect it as free text at checkout, trust it, and find out at quarter end. This post covers how EU VAT numbers are structured, why format validation and registry lookup are two different jobs, and how to run both in the order that costs least.
0202 What is a VAT number?
A VAT number is issued by a national tax authority to a business registered for Value Added Tax. It appears on invoices, in filings, and in the customer record of anyone selling B2B in the EU.
Every EU VAT number starts with a two-letter country code. That code is the ISO 3166 code for the member state, with one exception: Greece uses EL, not GR. After the prefix, each member state defines its own structure.
| Country | Format | Example |
|---|---|---|
| Germany | DE + 9 digits | DE123456789 |
| Netherlands | NL + 9 digits + B + 2 digits | NL123456789B01 |
| France | FR + 2-character key + 9 digits | FR12345678901 |
| Italy | IT + 11 digits | IT12345678901 |
| Spain | ES + letter/digit mix by entity type | ESA12345678 |
| Greece | EL + 9 digits | EL123456789 |
Several carry check digits computed with a country-specific algorithm. The Netherlands uses a weighted checksum. Italy uses a Luhn-style scheme. Which means most mistyped VAT numbers are mathematically detectable without contacting any registry.
One more prefix worth knowing: Northern Ireland uses XI for goods since Brexit. The rest of the UK's GB numbers are outside the EU system entirely.
0303 Why this check has teeth
VAT validation is one of the few data-quality checks with a direct tax consequence attached.
Since 1 January 2020, the EU's "quick fixes" made the customer's valid VAT number a substantive condition for zero-rating an intra-Community supply of goods. Before that, settled case law meant a missing number could not by itself remove the exemption. Now it can. If the number is not valid, the zero rating is lost and the VAT falls on you, on a sale where you collected none.
That is the difference between this and every other form validation in your product. A bad email address costs you a bounced message. A bad VAT number costs you the tax.
It also shows up in four other places:
- Invoice generation. A VAT number is mandatory on a compliant EU invoice. A malformed one gets the invoice sent back.
- Checkout tax logic. Your business-versus-consumer branch runs on this field.
- Supplier onboarding. A number captured once gets reused for the life of the relationship, and so does the error.
- CRM hygiene. Sales teams paste in spaces, dots and missing prefixes. The data degrades until something checks it.
0404 Two checks, not one
Here is the distinction that most posts on this topic blur.
Format validation asks whether a number could exist. It is instant, deterministic, has no external dependency, and catches typos.
Registry validation asks whether the number does exist and is currently registered for intra-EU trade. That answer comes from VIES, the European Commission's VAT Information Exchange System, which forwards the query to the issuing country's tax authority.
They fail differently, cost differently, and belong in different places.
What developers usually try
One regex for the whole EU. Fast to write, and not a validation. A pattern loose enough to accept all 27 member states accepts almost anything.
Per-country regex plus checksums. Genuinely effective, and now you maintain tax-format logic in your codebase forever. Formats change and somebody has to notice.
Querying VIES directly. Authoritative, and harder than it looks. VIES is a proxy to 27 national systems. Individual countries go offline without warning. Some throttle. You have to handle a third state beyond valid and invalid, which is "could not check right now", and treating that as invalid blocks real customers.
A format validation API. No format logic to maintain, one integration, no registry behaviour to handle. It tells you the number could be real, not that it is.
The order that costs least
User input
│
├─▶ format check ──▶ invalid ──▶ reject at the form, instantly
│
└─▶ valid ──▶ registry lookup ──▶ registered / not registered / unavailable
Most of what users type wrong dies at the first gate. That means fewer calls into a registry that throttles you, and fewer users waiting on a national system that is down today.
0505 The format check
ApyHub's VAT Number Validation API takes a VAT number and returns a boolean. It checks structure and check digits. It does not perform a live registry lookup and it does not return a company name.
That is the honest description, and it is what makes it the right first gate.
bash
curl -X POST "https://api.eu.apyhub.com/apyhub/validate-vat-number" \
-H "apy-token: $APY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"vat":"NL123456789B01"}'json
{ "data": true }A malformed number returns { "data": false }.
In Node:
javascript
const res = await fetch("https://api.eu.apyhub.com/apyhub/validate-vat-number", {
method: "POST",
headers: {
"apy-token": process.env.APY_TOKEN,
"Content-Type": "application/json"
},
body: JSON.stringify({ vat: "NL123456789B01" })
});
const { data } = await res.json(); // true or falseCall it on blur, before submit. The user fixes their typo while they are still looking at the field.
Try it in the playground. Free tier, no card.
0606 The registry lookup
Once a number is well-formed, the question becomes whether it is registered and who holds it. The VAT Company Lookup API returns the registered company name, address and country code alongside validity.
bash
curl -X POST "https://api.eu.apyhub.com/apyhub/lookup-vat-company" \
-H "apy-token: $APY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"vat":"NL123456789B01"}'Use the returned name for two things. Put the registered legal entity on the invoice, which is what compliant invoicing requires in most member states. And compare it with the account name in front of you, because a company name that matches nothing you recognise means someone has entered a VAT number that is not theirs.
Three registry behaviours to code for:
- Germany and Spain return no name or address. Both withhold trader details through VIES on data protection grounds. A valid German number comes back with empty identity fields. That is policy, not a failed lookup, and your code should not treat it as an error.
- A new registration can read as invalid. Germany, Italy and Spain register domestically first and activate for intra-EU trade separately. A real customer can fail for days. Charge VAT until the number validates rather than assuming fraud.
- "Unavailable" is not "invalid". When a national registry is unreachable, retry later and queue the number. Rejecting the customer instead is how you lose a good one.
0707 Checking a list
For CRM cleanup, supplier imports or a periodic re-check, the Validate EU VAT Batch API takes up to 10 numbers per request and returns a result per number, with failed lookups flagged separately from invalid ones.
javascript
async function validateAll(vatNumbers) {
const results = [];
for (let i = 0; i < vatNumbers.length; i += 10) {
const res = await fetch("https://api.eu.apyhub.com/apyhub/validate-vat-batch", {
method: "POST",
headers: {
"apy-token": process.env.APY_TOKEN,
"Content-Type": "application/json"
},
body: JSON.stringify({ vat_numbers: vatNumbers.slice(i, i + 10) })
});
const { data } = await res.json();
results.push(...data);
}
return results;
}Registrations get cancelled and nobody writes to tell you, so a quarterly pass over active B2B customers and suppliers is worth scheduling.
0808 Why run it through ApyHub
- No per-country format logic in your repository. The 27 patterns and their check-digit algorithms stay outside your codebase.
- A cheap first gate. Filtering malformed input before a registry call cuts the volume you send into a throttled external system.
- One credential across the flow. The same
apy-tokencovers VAT, IBAN, SWIFT/BIC and email validation, which is most of an EU onboarding form. - Machine-readable certification. Every endpoint publishes structured attributes for data residency, retention, sub-processors and alignment with GDPR, SOC 2 and ISO 27001. That matters for a field that is personal data when the registrant is a sole trader.
- MCP-ready by default. An agent handling invoicing or onboarding can call the endpoint without a hand-written tool definition.
0909 Use cases
- SaaS and ecommerce checkout. Validate on blur so the reverse-charge branch never runs on a malformed ID.
- Invoice generation. Gate invoice creation on a valid number, and pull the registered entity name from the lookup.
- Supplier onboarding. Validate at capture, so the stored number is well-formed from day one.
- CRM cleanup. Batch-validate the table, fix the malformed rows, then run registry checks on the rest.
- Agentic finance workflows. An agent processing supplier invoices checks the VAT field as part of its flow rather than passing an unverified value downstream.
1010 Getting started
- Create a free ApyHub account at apyhub.com. No card required.
- Open workspace settings, go to API Keys, and generate a credential. Save the
apy-tokenvalue: secrets are generated on the fly and not stored in plain text. - Test in the playground on the VAT Number Validation API page with a number from your own records.
- Call it on blur in your checkout or onboarding form.
- Layer the company lookup behind it for registration status and the legal entity name.
1111 Conclusion
VAT validation splits into two questions that are easy to conflate: is this number well-formed, and is it currently registered. Different costs, different failure modes, different right answers about where each belongs.
Put the format check at the form, where it is instant and always available. Put the registry lookup behind it, where its downtime cannot block a user mid-signup. Do both and the number on the invoice is one you can defend.
Try the VAT validation APIs. Free tier, no card.
1212 FAQ
What is a VAT number? The identifier a national tax authority assigns to a VAT-registered business. In the EU it starts with a two-letter country code followed by a country-specific sequence.
Does the validation API check registration with VIES? No. It validates structure and check digits. For live registration status, use the VAT Company Lookup API, which returns validity plus the registered company details.
Why not just use a regular expression? Each of the 27 member states has its own format, and several carry country-specific check-digit algorithms. That is permanent maintenance for a check that is not your product.
Does Greece use GR? No. Greek VAT numbers use EL. It is the most common single mistake in hand-rolled EU VAT validation.
Why did a valid VAT number come back with no company name? Germany and Spain do not disclose trader names or addresses through VIES. The number is confirmed; the identity fields stay empty.
Why does a real customer's number fail? Most often because it has not been activated for intra-EU trade yet. Germany, Italy and Spain activate separately from domestic registration, which can take days.
Do I have to check VAT numbers before invoicing? For zero-rated intra-Community supplies of goods, yes. Since January 2020 the customer's valid number is a substantive condition for the exemption.
Can I check UK VAT numbers? GB numbers are outside the EU system since Brexit. Northern Ireland numbers for goods use the XI prefix and are still covered. HMRC runs a separate service for GB.
How often should stored numbers be re-checked? Quarterly for active B2B customers and suppliers, plus at onboarding and before large transactions.
Does ApyHub store the VAT numbers I submit? Data handling, retention and residency are published as machine-readable certification attributes on the service page, alongside GDPR, SOC 2 and ISO 27001 alignment.
1313 About ApyHub
ApyHub is a curated API catalog and the trusted operational layer for external APIs. The catalog covers 430+ live services and 1,000+ endpoints across 20 categories, from AI and data extraction to document conversion, image and video processing, and validation, all under a single subscription priced in atoms.
Every endpoint ships with machine-readable certification covering data residency, retention, sub-processors and standards alignment across GDPR, SOC 2 and ISO 27001. Every endpoint is MCP-ready by default, so AI agents can discover and call it without a wrapper.
ApyHub is headquartered in Amsterdam, with offices in the Netherlands, Greece and India, and serves 65,000+ developer workspaces every month. There is a free tier and no card is required to start.
Have an API of your own? Become a provider.
