DEV Community

Daniel
Daniel

Posted on

How to Validate Spanish NIF, NIE, CIF and IBAN in Any Programming Language (2026)

How to Validate Spanish NIF, NIE, CIF and IBAN in Any Programming Language (2026)

If you're building software for the Spanish market, sooner or later you'll need to validate fiscal documents. This guide covers everything: how the algorithms work, code examples in 4 languages, and the fastest way to add validation to any project.


What are NIF, NIE and CIF?

  • NIF — Tax ID for Spanish individuals (8 digits + 1 letter, e.g. 12345678Z)
  • NIE — Tax ID for foreign residents in Spain (X/Y/Z + 7 digits + letter, e.g. X1234567L)
  • CIF — Tax ID for Spanish companies (1 letter + 7 digits + 1 control char, e.g. A28015865). Also returns the company type: S.A., S.L., Cooperative, etc.
  • IBAN — Bank account number, 24 characters for Spanish accounts (e.g. ES9121000418450200051332)

Option 1: Implement it yourself

NIF validation (JavaScript)

const NIF_LETTERS = 'TRWAGMYFPDXBNJZSQVHLCKE';

function validateNIF(nif) {
  nif = nif.trim().toUpperCase();
  if (nif.length !== 9) return false;
  const number = parseInt(nif.slice(0, 8), 10);
  if (isNaN(number)) return false;
  return nif[8] === NIF_LETTERS[number % 23];
}

console.log(validateNIF('12345678Z')); // true
console.log(validateNIF('12345678A')); // false
Enter fullscreen mode Exit fullscreen mode

NIF validation (Python)

NIF_LETTERS = "TRWAGMYFPDXBNJZSQVHLCKE"

def validate_nif(nif: str) -> bool:
    nif = nif.strip().upper()
    if len(nif) != 9:
        return False
    try:
        number = int(nif[:8])
    except ValueError:
        return False
    return nif[8] == NIF_LETTERS[number % 23]

print(validate_nif("12345678Z"))  # True
Enter fullscreen mode Exit fullscreen mode

NIF validation (PHP)

function validateNIF(string $nif): bool {
    $letters = 'TRWAGMYFPDXBNJZSQVHLCKE';
    $nif = strtoupper(trim($nif));
    if (strlen($nif) !== 9) return false;
    $number = intval(substr($nif, 0, 8));
    return $nif[8] === $letters[$number % 23];
}

var_dump(validateNIF('12345678Z')); // bool(true)
Enter fullscreen mode Exit fullscreen mode

Option 2: Use an API (3 lines of code, any language)

If you don't want to implement and maintain the algorithms yourself — especially for CIF which is significantly more complex — you can use the Spain Document Validator API on RapidAPI. It's free for up to 500 requests/month.

JavaScript (fetch)

const response = await fetch(
  'https://spain-document-validator1.p.rapidapi.com/validate/nif?value=12345678Z',
  {
    headers: {
      'X-RapidAPI-Key': 'YOUR_API_KEY',
      'X-RapidAPI-Host': 'spain-document-validator1.p.rapidapi.com'
    }
  }
);
const data = await response.json();
console.log(data);
// { input: '12345678Z', valid: true, type: 'NIF' }
Enter fullscreen mode Exit fullscreen mode

Python (requests)

import requests

response = requests.get(
    'https://spain-document-validator1.p.rapidapi.com/validate/cif',
    params={'value': 'A28015865'},
    headers={
        'X-RapidAPI-Key': 'YOUR_API_KEY',
        'X-RapidAPI-Host': 'spain-document-validator1.p.rapidapi.com'
    }
)
print(response.json())
# {'input': 'A28015865', 'valid': True, 'type': 'CIF', 'entity_type': 'Sociedad Anónima'}
Enter fullscreen mode Exit fullscreen mode

PHP (cURL)

$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => 'https://spain-document-validator1.p.rapidapi.com/validate/iban?value=ES9121000418450200051332',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'X-RapidAPI-Key: YOUR_API_KEY',
        'X-RapidAPI-Host: spain-document-validator1.p.rapidapi.com'
    ],
]);
$response = json_decode(curl_exec($curl));
// $response->bank_name = "CaixaBank"
Enter fullscreen mode Exit fullscreen mode

API response examples

NIF:

{ "input": "12345678Z", "valid": true, "type": "NIF" }
Enter fullscreen mode Exit fullscreen mode

CIF:

{
  "input": "A28015865",
  "valid": true,
  "type": "CIF",
  "entity_type": "Sociedad Anónima"
}
Enter fullscreen mode Exit fullscreen mode

IBAN:

{
  "input": "ES9121000418450200051332",
  "valid": true,
  "type": "IBAN",
  "country": "ES",
  "formatted": "ES91 2100 0418 4502 0005 1332",
  "bank_code": "2100",
  "branch_code": "0418",
  "bank_name": "CaixaBank"
}
Enter fullscreen mode Exit fullscreen mode

When to use the API vs implementing it yourself

DIY API
Setup time 2-4 hours 5 minutes
Works in any language Requires separate lib per lang Yes
CIF entity type info Extra work Included
IBAN bank name lookup Very complex Included
Maintenance when rules change Your problem Automatic

The free tier (500 req/month) is enough for most small projects. Paid plans start at $9/month for 15,000 requests.


The full API documentation and interactive playground is available at spanish-validation-api.vercel.app/docs.

Top comments (0)