Why We Built an API for Spanish Fiscal ID Validation Instead of Just Implementing It
<p>A few months ago I was integrating fiscal identifier validation into a project. I googled it, found a 30-line JavaScript function, copied it, tested it with four cases, and it worked. I dropped it into the codebase and forgot about it.</p> <p>Three months later, a user emailed us: their CIF wasn't validating. It was a perfectly valid CIF.</p> <p>That's when I understood there's a difference between <strong>implementing</strong> validation and <strong>maintaining it correctly</strong>.</p> <h2> The problem isn't that it's hard </h2> <p>Validating a NIF seems straightforward: 8 digits, one letter, modulo 23. Any developer can implement it in ten minutes.</p> <p>The problems appear when you scratch the surface:</p> <p><strong>NIF:</strong> the basic algorithm works, but there are special f
A few months ago I was integrating fiscal identifier validation into a project. I googled it, found a 30-line JavaScript function, copied it, tested it with four cases, and it worked. I dropped it into the codebase and forgot about it.
Three months later, a user emailed us: their CIF wasn't validating. It was a perfectly valid CIF.
That's when I understood there's a difference between implementing validation and maintaining it correctly.
The problem isn't that it's hard
Validating a NIF seems straightforward: 8 digits, one letter, modulo 23. Any developer can implement it in ten minutes.
The problems appear when you scratch the surface:
NIF: the basic algorithm works, but there are special formats — K, L and M NIFs for specific cases — that most implementations simply ignore.
NIE: starts with X, Y or Z, then follows the NIF algorithm with substitution. Most regex you'll find online accept 7 or 8 digits interchangeably, when the correct format depends on the prefix.
CIF: this is where almost everything breaks. The control character can be a letter or a digit depending on the entity type (first letter of the CIF). Most implementations accept either for all types — which is incorrect. Additionally, when (10 - sum % 10) % 10 === 0, the control character should be J in certain cases — an edge case that produces silent bugs that are extremely hard to track down.
IBAN: the MOD-97 algorithm requires arithmetic with very large numbers. In JavaScript you need BigInt, and in environments where it's unavailable or poorly implemented, it fails without a visible error.
None of these bugs surface in development. They surface in production, with real identifiers from real users.
The silent bug is the worst kind of bug
When a validation fails visibly — throws an exception, returns an error — you catch it and fix it. The real problem with fiscal validation bugs is that they accept invalid identifiers without warning.
A user enters a CIF with an incorrect control digit. Your code says "valid". The data goes into the database. Months later, when you try to use that data for a fiscal operation, the problem surfaces — but now you have no idea where it came from.
The maintenance nobody budgets for
Even if you implement everything correctly today, there's another problem: the rules can change.
Spain has updated fiscal identifier formats in the past. NIE formats have evolved. When that happens, someone has to update the code — and that someone might not be the person who wrote it, or be on the same team, or remember why each decision was made.
With an API, that's the API maintainer's problem. You consume the endpoint, they keep the algorithms up to date.
What we built
We built Valix — a REST API that validates NIF, NIE, CIF and IBAN using the official Spanish algorithms, with automatic type detection and a structured JSON response.
import requests
response = requests.post( "https://api.getvalix.io/v1/validate/trial", json={ "items": [ {"value": "12345678Z", "type": "AUTO"}, {"value": "X1234567L", "type": "AUTO"}, {"value": "A12345674", "type": "AUTO"}, {"value": "ES9121000418450200051332", "type": "AUTO"} ] } )
result = response.json() for item in result["results"]: status = "valid" if item["valid"] else f"invalid: {', '.join(item['errors'])}" print(f"{item['value']} → {item['detected_type']} — {status}")`
Enter fullscreen mode
Exit fullscreen mode
Output:
12345678Z → NIF — valid X1234567L → NIE — valid A12345674 → CIF — valid ES9121000418450200051332 → IBAN — valid12345678Z → NIF — valid X1234567L → NIE — valid A12345674 → CIF — valid ES9121000418450200051332 → IBAN — validEnter fullscreen mode
Exit fullscreen mode
The trial endpoint requires no registration or API key — 50 validations per day per IP so you can test it before committing to anything.
When does it make sense to implement it yourself?
Being honest: if your validation volume is very low, you're always validating the same identifier type, and you have exhaustive tests with real-world cases, implementing it internally can make sense.
But if you're validating identifiers from production users, mixing types (NIF + NIE + CIF + IBAN), or simply don't want to spend time maintaining this — an API is the more sensible choice.
Resources
-
API and documentation: getvalix.io
-
Code examples in Python, JavaScript, PHP and cURL: github.com/getvalix/valix-examples
-
JavaScript/TypeScript SDK: npm @valix/sdk
Disclaimer: I'm the author of Valix.
Sign in to highlight and annotate this article

Conversation starters
Daily AI Digest
Get the top 5 AI stories delivered to your inbox every morning.
More about
availableupdateproductA standards-aligned cryptographic human-authorization layer for agentic AI - biometricupdate.com
<a href="https://news.google.com/rss/articles/CBMiswFBVV95cUxNUnNSX0N5ZkhRYkpKcGNOVDdkazFCTVpobnp0b1NuZW9ma3ZzVWgwMHF0cnAzZk9jOUZGYUhZSzF2VldNS0NIZHViSmI5ZUxPa2llSHBKaU5qWlhpYUprS3hSZW1EcHVwYlZZZlVRS211VUN3SXlzQjZPVkVZd0xjQTQ4eExLbjhmNXdtWUJKVDVxWEpvNENkQUMwdEhjV0xLOTU2Rm5XaU1Bb1FwNkZaODlUTQ?oc=5" target="_blank">A standards-aligned cryptographic human-authorization layer for agentic AI</a> <font color="#6f6f6f">biometricupdate.com</font>
Exclusive | The Sudden Fall of OpenAI’s Most Hyped Product Since ChatGPT - WSJ
<a href="https://news.google.com/rss/articles/CBMiogNBVV95cUxPYTkyeWQ0cXFBRWZoa0FiVzMtdnA0S05WNm12SHFNY0pleGUyOWRnRVRObUhMWWh0ei1FZl83cTQ4YTBSREVfWjgwZTVyMW9ZWFJlRG5FMEh0SXhCOExfVlNTNlFTQVR0RjUtdWtDSzFtX0xhV2JZZHVnOGNNVVgydlowZlNtSHh6bE9ZSjRhYmJaY19xTjJjaGduSXczUVcyS0NkX2cxWm5vcU9hMnNhQ01zTTdfNmNhb3lhaEhiN3E0LTBxRkthU2Q1TXA0RzI5bDVTcnRLS2ZHUjlCV1hDUTR5WlZFeTVHUE9sMDY2eU9aWU1McE9lR19hYzhqQTBOMkF6c2p6bmM4cEw4aTdZZUtHQU1STU1SN0tQcWdwNGhuNnRuVk9hcVJaeGlKMGRtVDhYQmtHSlVhbzd5VElUV0pFdndXRWlkV00zS2RRT2tlYVBYYnpkQWJFSXFwZmdjZlBfV1ZMVUo5MFZmRUVNZXhmcTNBNXY5RmNZVDFnbmgyTWh4Y2RJcjlkSi1uSkpIa3lXNEFQSGU3bTllR0RBbGNB?oc=5" target="_blank">Exclusive | The Sudden Fall of OpenAI’s Most Hyped Product Since ChatGPT</a> <font color="#6f6f6f">WSJ</font>
Exclusive | The Sudden Fall of OpenAI’s Most Hyped Product Since ChatGPT - WSJ
<a href="https://news.google.com/rss/articles/CBMiogNBVV95cUxPWjRJSWkxWXVWZVJQeGx4a3dNaWZHZ3F2RzdndWZKM1dnbUJicGxicHFZYTk0OTFUZDU4ZlNYYnJkQ2JnYzZZaXFUZzdzbWt4RlRlTS1uQjMyUnhQLWI4Tl9CQ3VtX1podDQ3WkdDQzlCTEFXMUxnbXpUZk9uTy1hLXR0UDhmWVNMRFRBR0NaUVBpMGZxMVhQQkZfa1VHOVFYUGk1YW1TbnkzRWcweTBKNThnRnRHYWExb2dFNEp6dDh3X2pqRkx2OUxoTnVNNkh2NWx5VGhFVnduS20tbWVNdmZGd3VUbzZzZHdDQ2tVYlJta2pmTHZ6dEtqNnlRc1lYQ1NBemV4UFpGa0dIWGpTTmtxNElUX3p2bFBqQTViMV9wenB1NWtsMXdzcFBvT0lQSnlNS003bjNmRE9IeDNrb25fMGsxV2R6Q0pJdlp6dlNrNEY4UW1SQy1ocW1BQlhiZTFTQ094ck5YenhVUzlKRDdPbXgwQmQySlR0Zm95dnVyMnIydVlIeUhRTjh5bmJSVWdwdTFQYUlwWGZIVlpTUXVB?oc=5" target="_blank">Exclusive | The Sudden Fall of OpenAI’s Most Hyped Product Since ChatGPT</a> <font color="#6f6f6f">WSJ</font>
Knowledge Map
Connected Articles — Knowledge Graph
This article is connected to other articles through shared AI topics and tags.
More in Releases
Bureau Veritas Launches an Independent AI Assessment Offering for European Enterprises, Developed in Partnership with Amazon Web Services (AWS) - Business Wire
<a href="https://news.google.com/rss/articles/CBMiowJBVV95cUxNU19VS3BVRDdwM2ZLTmkyTXdlS0dMbDJkUFZiaDNIWXk1X1FZbEI1ZnByc0pVb2JQTHlnd2k1RFNJektyb0FwNXlaQnp1UXFXdFJweUd2R1FmTFlnSlNJN25BR2pFek95dWhJZGFGQjdQRWVPSlRHb2dsdE1Xa1pfNUFFMi1hS1VaNmpkeDJlaS01cTVtaC1Ka2NpWWFMbDNSRjNYc3lqNEVjUFVERTRMc2VXOUdDekJfZjg5VjlZWmlJV3V3dF9uWHV1SW5hS1NDVDVTNE42SXRHMXhfN1RLS2F6SmdiaHluQnpVbi1wRGFnZktNNU9BX2ctRi0zRUxBS1phbHZKV1hZVDh6cjVTSDh0YkJrbnFkd2hhR2t6c1pvQ0E?oc=5" target="_blank">Bureau Veritas Launches an Independent AI Assessment Offering for European Enterprises, Developed in Partnership with Amazon Web Services (AWS)</a> <font color="#6f6f6f">Business Wire</font>
Did Alibaba just kneecap its powerful Qwen AI team? Key figures depart in wake of latest open source release - VentureBeat
<a href="https://news.google.com/rss/articles/CBMiqwFBVV95cUxPdjlCQWxQTnFtaDJTWGczNGtXTENNY3l2c2gwTnd4d2JyaXNCVXZobGhYR2VYNTgwdi1hSmp6Y1JfMVNrek1aN0JYcjJOc3JFek5RTnhsTmdZYk9JYVdiM0laNzlNVHE0b1M3OEYxMGZ5SXhkUDFQUDFyQmxvMHRzbEw1ZThmcXdGbW1DTXJEVDlaWmlCNnZnT1A4UzhmanVFZlZKVmQtYU5acEU?oc=5" target="_blank">Did Alibaba just kneecap its powerful Qwen AI team? Key figures depart in wake of latest open source release</a> <font color="#6f6f6f">VentureBeat</font>

缓存架构深度指南:如何设计高性能缓存系统
<h1> 缓存架构深度指南:如何设计高性能缓存系统 </h1> <blockquote> <p>在现代分布式系统中,缓存是提升系统性能的核心组件。本文将深入探讨缓存架构的设计原则、策略与实战技巧。</p> </blockquote> <h2> 为什么要使用缓存? </h2> <p>在软件系统中,缓存的本质是<strong>用空间换时间</strong>。通过将频繁访问的数据存储在高速存储介质中,减少对慢速数据源的访问次数,从而显著提升系统响应速度。</p> <p>典型场景:</p> <ul> <li>数据库查询结果缓存</li> <li>API响应缓存</li> <li>会话状态缓存</li> <li>计算结果缓存</li> </ul> <h2> 缓存架构设计原则 </h2> <h3> 1. 缓存层级策略 </h3> <p>现代系统通常采用多级缓存架构:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>┌─────────────────────────────────────────────┐ │ CDN (边缘缓存) │ ├─────────────────────────────────────────────┤ │ Redis/Memcached │ ├─────────────────────────────────────────────┤ │ 本地缓存 │ ├─────────────────────────────────────────────┤ │ 数据库 │ └─────────────────────────────────────────────┘ </code></pre> </div> <p><strong>原则<


Discussion
Sign in to join the discussion
No comments yet — be the first to share your thoughts!