Irmu
Free tool

Spanish CIF / NIF / NIE validator

Check Spanish tax IDs one by one or in bulk. For company CIFs, the first letter tells you the legal form, so the tool also sorts your list by company type.

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

  • NIF (8 digits + letter) and NIE (X/Y/Z + 7 digits + letter) are checked against the mod-23 letter table.
  • CIF (letter + 7 digits + control) uses the AEAT control-digit algorithm. Some letters must end in a digit, some in a letter.
  • The first CIF letter gives the legal form, and digits 2-3 are the province code where it was issued.
  • An ES prefix (the VAT form) is accepted and stripped.

To confirm a number is registered and active, use AEAT. The Spanish Tax Agency and the Registro Mercantil (BORME) confirm whether a CIF belongs to an active company.

Categorisation

CIF letters and legal forms

ASociedad Anónima (public limited company)
BSociedad Limitada (private limited company)
C / DGeneral / limited partnership
EComunidad de bienes
FCooperative
GAssociation or foundation
HOwners' association
JCivil partnership
N / WForeign entity / permanent establishment
P / Q / SLocal authority / public body / central government
RReligious institution
U / VJoint venture (UTE) / other
Code examples

Run the same checks in your own code

import re

TYPES = {"A": "S.A.", "B": "S.L.", "F": "Cooperative", "G": "Association/foundation"}

def cif_ok(cif: str) -> bool:
    c = re.sub(r"[\s.-]", "", cif.upper())
    if not re.fullmatch(r"[ABCDEFGHJNPQRSUVW]\d{7}[0-9A-J]", c):
        return False
    total = 0
    for i, d in enumerate(map(int, c[1:8])):
        if i % 2:                     # even positions: add
            total += d
        else:                         # odd positions: double, add the digits
            total += sum(divmod(d * 2, 10))
    digit = (10 - total % 10) % 10
    letter = "JABCDEFGHI"[digit]
    if c[0] in "NPQRSW": return c[8] == letter
    if c[0] in "ABEH":   return c[8] == str(digit)
    return c[8] in (letter, str(digit))

def nif_ok(nif: str) -> bool:
    n = nif.upper().replace("X", "0", 1).replace("Y", "1", 1).replace("Z", "2", 1)
    return bool(re.fullmatch(r"\d{8}[A-Z]", n)) and "TRWAGMYFPDXBNJZSQVHLCKE"[int(n[:8]) % 23] == n[8]

print(cif_ok("B-12345674"), TYPES.get("B"), nif_ok("12345678Z"))  # True S.L. 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": "Find the company's legal name, CIF/NIF and registered address on this page (usually in the Aviso legal). Return JSON: {name, cif, address}.",
    },
    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.