Irmu
Free tool

EU & UK VAT number validator

Paste a list of VAT numbers, or a whole page, and check each one's country prefix, format and checksum. Covers all 27 EU member states plus GB and XI (Northern Ireland).

0/0 valid
One number per line
Results

Nothing yet. Paste numbers or a page on the left, or load the sample.

Runs entirely in your browser. A passing check means the number is well-formed, not that it is registered or active. Categories are inferred from the number format.

How it works

What gets checked

  • The two-letter prefix selects the country rules (Greece uses EL, not GR; Northern Ireland uses XI).
  • Format is checked for every country. Checksums are verified for DE, ES, FR, IT, BE, PL, PT and GB/XI; other countries get a format-only result, labelled as such.
  • Spanish VAT numbers also show the legal form encoded in the CIF letter.
  • Extraction mode looks for numbers next to labels such as VAT, TVA, IVA, USt-IdNr., BTW or NIP.

To confirm a number is registered and active, use EU VIES. The European Commission's VIES service confirms whether an EU VAT number is active. UK numbers are checked with HMRC.

Categorisation

What the prefix tells you

DE, FR, IT, ES, BE, PL, PT, GBFormat plus checksum
Other EU prefixesFormat only
XINorthern Ireland trader (post-Brexit)
GBGD / GBHAUK government department / health authority
Code examples

Run the same checks in your own code

import re

def de_ok(n: str) -> bool:          # ISO 7064 MOD 11,10
    product = 10
    for d in n[:8]:
        s = (int(d) + product) % 10 or 10
        product = (2 * s) % 11
    return (11 - product) % 10 == int(n[8])

def gb_ok(n: str) -> bool:          # mod 97 with the 9755 variant
    total = sum(int(d) * w for d, w in zip(n[:7], range(8, 1, -1))) + int(n[7:9])
    return total % 97 == 0 or (total + 55) % 97 == 0

def validate_vat(raw: str) -> bool:
    v = re.sub(r"[\s.-]", "", raw.upper())
    cc, rest = v[:2], v[2:]
    if cc == "DE": return bool(re.fullmatch(r"[1-9]\d{8}", rest)) and de_ok(rest)
    if cc in ("GB", "XI"): return bool(re.fullmatch(r"\d{9}(\d{3})?", rest)) and gb_ok(rest)
    raise ValueError("add the rule for " + cc)

print(validate_vat("DE 136 695 976"), validate_vat("GB980780684"))  # True True
With Irmu

Collect the numbers from company websites

A browser can't fetch other sites for you. Irmu fetches the page, handles rendering and blocking, and ai_query (+5 credits) returns the fields you ask for.

collect_ids.py
# Fetch a company's legal page with Irmu and let ai_query pull the IDs out,
# then validate them locally with the functions above.
import os, requests

resp = requests.get(
    "https://app.irmu.com/api/crawl",
    headers={"Authorization": f"Bearer {os.environ['IRMU_API_KEY']}"},
    params={
        "url": "https://example.com/legal",
        "js": "true",
        "ai_query": "List every VAT number on this page with the company name next to it. Return JSON: [{company, vat}].",
    },
    timeout=120,
)
resp.raise_for_status()
print(resp.json()["data"])
FAQ

Questions

Build a verified company database

Fetch legal pages at scale with one API. 200 free credits every month, no card required.