Español · English
Validación del RUC paraguayo en el navegador o en el servidor. Cero dependencias.
Detecta un RUC mal tipeado sin llamar a la DNIT. Atrapa dígitos cambiados y transposiciones, que son la mayoría de los errores de carga en un formulario.
import { esValido, formatear, analizar } from "@findtek/ruc-paraguay";
esValido("80012345-0"); // true
esValido("80012345-7"); // false — dígito equivocado
esValido("80012354-0"); // false — dos dígitos transpuestos
formatear("80.012.345"); // "80012345-0"
analizar("80012345-7");
// { valido: false, base: "80012345", digito: 7,
// digitoEsperado: 0, formateado: "80012345-0" }npm install @findtek/ruc-paraguayEl RUC es un número base más un dígito verificador calculado con módulo 11.
1. Normalizar 80012345 solo 0-9 y A-Z; las letras pasan a su código ASCII
2. Pesar de derecha a izquierda, por 2, 3, 4 … 11, y vuelta a 2
3. Sumar 122
4. resto = 122 % 11 = 1
resto > 1 → dígito = 11 - resto
resto ≤ 1 → dígito = 0
El paso 2, desplegado:
8 0 0 1 2 3 4 5 ← base
×9 ×8 ×7 ×6 ×5 ×4 ×3 ×2 ← pesos, arrancando por la derecha
─────────────────────────────────────
72 + 0 + 0 + 6 + 10 + 12 + 12 + 10 = 122
122 % 11 = 1 → como el resto es 1, el dígito es 0 → 80012345-0
Las cédulas antiguas tienen letra (A1234567). Se convierten usando el código
ASCII de la letra, no su posición en el abecedario: A → 65, así que
A1234567 se procesa como 651234567. Varias implementaciones dando vueltas por
internet usan A = 1 y fallan en esos casos.
| Función | Devuelve | Lanza |
|---|---|---|
calcularDigito(base, baseMax?) |
El dígito verificador de una base | RucInvalidoError si la base queda vacía |
esValido(ruc) |
boolean |
Nunca — ante basura devuelve false |
analizar(ruc) |
RucAnalizado con el detalle |
RucInvalidoError si no hay base reconocible |
formatear(ruc) |
El RUC canónico base-dígito |
RucInvalidoError si no hay base reconocible |
Las cuatro toleran puntos, espacios, minúsculas y el guion opcional.
El algoritmo se corrió contra el padrón público entero de la DNIT, los 10
archivos (ruc0 … ruc9) de julio de 2026:
| Estado del contribuyente | Registros | Discrepancias |
|---|---|---|
| ACTIVO | 877.351 | 0 |
| SUSPENSION TEMPORAL | 407.758 | 0 |
| BLOQUEADO | 30.997 | 0 |
| CANCELADO | 678.895 | 2 |
| CANCELADO DEFINITIVO | 11 | 0 |
| Total | 1.995.012 | 2 |
99,9999 % de coincidencia. Las 2 discrepancias son 80045405-1 y
80044639-0, ambas de contribuyentes cancelados: son errores de carga del
propio padrón, no del algoritmo. Ningún RUC vigente falla.
No hace falta instalar nada — Node 22+ ejecuta TypeScript de forma nativa:
node --test --experimental-strip-types test/*.test.tsSon 17 tests. La suite incluye 2.128 RUC reales de contribuyentes activos, con 128 casos de
base con letra. El fixture (test/padron-muestra.txt) contiene solo el número
base y el dígito verificador: sin nombres ni ningún otro dato personal.
Esta librería comprueba que un RUC esté bien escrito. No verifica que exista ni a quién pertenece — para eso hay que consultar a la DNIT.
Para el código de control de la factura electrónica:
sifen-cdc.
Padrón público de la DNIT (ex-SET): https://www.dnit.gov.py/web/portal-institucional/listado-de-ruc-con-sus-equivalencias
MIT — FindTek, San Lorenzo, Paraguay 🇵🇾