Get a Company's EU VAT Number from Its Company Number: the Rules for 10 Countries (with Code) Your onboarding form asks for a company number, your invoicing system needs a VAT number, and the customer typed only one of them. In many European countries the VAT number is not a separate secret: it is the company's own identifier in a fixed format. In others there is no rule at all. Here are the rules, a function you can paste, and the one thing a derived number cannot tell you. The rules Country Built from VAT number Example Spain NIF (company letters A–W) ES + NIF ESA46103834 France SIREN (9 digits) FR + 2-digit key + SIREN FR27552032534 Poland NIP (10 digits) PL + NIP PL7740001454 Norway organisasjonsnummer (9 digits) NO + number + MVA NO923609016MVA Finland Y-tunnus 1234567-8 FI + the 8 digits FI01120389 Sweden organisationsnummer (10 digits) SE + number + 01 SE556810898801 Belgium enterprise number (10 digits) BE + number BE0202239951 Croatia OIB (11 digits) HR + OIB HR18928523252 Denmark CVR (8 digits) DK + CVR DK24256790 Switzerland UID CHE-123.456.789 UID + MWST (TVA/IVA) CHE103867266MWST No rule exists for the UK (a VAT number is its own registration with HMRC), Ireland, Slovakia (the IČ DPH is not derived from the IČO) or Estonia (the KMKR is not the registry code). There you need the number from the company or from a register that publishes it. France: the key The only rule with arithmetic. The two-digit key is (12 + 3 × (SIREN mod 97)) mod 97: def fr_vat(siren: str) -> str: key = (12 + 3 * (int(siren) % 97)) % 97 return f"FR{key:02d}{siren}" assert fr_vat("552032534") == "FR27552032534" # Danone Enter fullscreen mode Exit fullscreen mode All ten as one function import re def vat_from_company_number(country: str, number: str) -> str | None: """The VAT number a company's identifier implies, or None where no rule exists.""" s = re.sub(r"[\s.\-/]", "", number or "").upper() d = re.sub(r"\D", "", s) if country == "ES": return f"ES{s}" if re.fullmatch(r"[ABCDEFGHJNPQRSUVW]\d{7}[0-9A-J]", s) else None if country == "FR" and len(d) == 9: return f"FR{(12 + 3 * (int(d) % 97)) % 97:02d}{d}" rules = {"PL": (10, "PL", ""), "NO": (9, "NO", "MVA"), "FI": (8, "FI", ""), "SE": (10, "SE", "01"), "BE": (10, "BE", ""), "HR": (11, "HR", ""), "DK": (8, "DK", ""), "CH": (9, "CHE", "MWST")} if country in rules and len(d) == rules[country][0]: n, prefix, suffix = rules[country] return f"{prefix}{d}{suffix}" return None Enter fullscreen mode Exit fullscreen mode Note the Spanish check: a NIF that starts with X, Y or Z is a foreigner's personal NIE, never a company VAT number. The one thing a derived number cannot tell you The format is right; whether the company is actually registered for VAT is a separate fact. Plenty of small companies, holding companies and non-profits are not. Before you put a derived number on an invoice or zero-rate a cross-border sale, check it against VIES, the European Commission's validation service: curl "https://api.prometiam.com/functions/v1/risk-api/vat/FR27552032534" \ -H "Authorization: Bearer $PROMETIAM_API_KEY" Enter fullscreen mode Exit fullscreen mode Two registers answer the registration question themselves. Norway's register flags whether a company is in the VAT register, and Finland's register says so for many companies. In both, a company the register marks as not VAT-registered has no VAT number at all, so building one would be wrong. Or let the API do it Every company object the Prometiam Risk API returns now carries vat_number and vat_number_source: register when the register publishes the number (Estonia) or confirms the company is VAT-registered (Norway, Finland, Belgium), rule when it was built with the rules above, and null where the register says the company is not VAT-registered or no rule exists (UK, Ireland, Slovakia). Search, lookup and VIES checks run on the free 14-day trial (1,000 requests; sign up). For a one-off check without code there is a free VAT number checker.
Get a Company's EU VAT Number from Its Company Number: the Rules for 10 Countries (with Code)
Full Article
Original Source
Read the full article at Dev →KhanList aggregates and links to publicly available news content. We do not host full articles from third-party sources. Always verify important information with original sources.