METODOLOGÍA · ARGENTINA

Dígito verificador del CUIT

El CUIT argentino usa el algoritmo Mod-11 con pesos fijos para calcular su dígito verificador. Esta página explica el algoritmo conceptualmente, incluye un ejemplo numérico completo, y enumera los 14 edge cases que hacen que implementaciones simples fallen en producción.

El algoritmo

El CUIT (Código Único de Identificación Tributaria) es el identificador fiscal argentino emitido por AFIP, la autoridad tributaria de Argentina. Tiene 11 dígitos en el formato XX-XXXXXXXX-V, donde XX es el prefijo de tipo de entidad, XXXXXXXX son 8 dígitos del DNI base, y V es el dígito verificador.

El algoritmo de verificación es Mod-11 con pesos fijos. Las posiciones 1 a 10 se multiplican por los pesos [5, 4, 3, 2, 7, 6, 5, 4, 3, 2] respectivamente. Se suman los productos, se calcula el resto de dividir por 11, y el dígito verificador es 11 menos ese resto — con dos excepciones: si el resultado es 11, el dígito es 0; si es 10, el CUIT es estructuralmente inválido.

Posición1  2  3  4  5  6  7  8  9  10
Peso5  4  3  2  7  6  5  4  3   2

Ejemplo numérico paso a paso

Calculamos el dígito verificador para el CUIT 20-12345678-?.

Dígitos2  0  1  2  3  4  5  6  7  8
Pesos5  4  3  2  7  6  5  4  3  2
Productos10 0  3  4 21 24 25 24 21 16
Suma10+0+3+4+21+24+25+24+21+16 = 148
148 mod 11= 5 (148 = 13×11 + 5)
Dígito verificador11 − 5 = 6
CUIT20-12345678-6

Pseudocódigo

weights = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2]
sum = Σ digit[i] × weights[i]  for i in 0..9
remainder = sum mod 11
if remainder == 0   → check_digit = 0
if remainder == 1   → INVALID (no valid CUIT exists for this prefix/base)
else                → check_digit = 11 − remainder
return check_digit == provided_digit

Edge cases que una implementación simple no maneja

  • mod 11 = 1 → resultado 10: ningún dígito decimal puede ser 10. Muchas implementaciones naive no manejan este caso y devuelven resultados incorrectos.
  • mod 11 = 0 → resultado 11: se mapea a 0, no a 11. Implementaciones que no hacen este mapeo rechazan CUITs válidos.
  • Prefijos no asignados: no todos los códigos de dos dígitos son válidos. Prefijos como 11, 12, 13 no están asignados por AFIP. Un CUIT puede pasar el checksum pero usar un prefijo reservado.
  • CUIT vs CUIL: ambos comparten el mismo algoritmo Mod-11 y los mismos pesos, pero los prefijos válidos difieren. Los prefijos 20/23/24/27 son personas físicas; 30/33/34 son personas jurídicas. CUIL admite prefijos adicionales para extranjeros.
  • Prefijos históricos deprecated: algunos prefijos emitidos por AFIP en los años 90 ya no se asignan pero siguen circulando en bases de datos legacy. Rechazarlos rompe integraciones con sistemas antiguos.
  • Formatos de entrada variados: 20-12345678-6, 20123456786, 20 12345678 6, (20) 12345678-6 — todos representan el mismo CUIT. La normalización previa a la validación es obligatoria.
  • Caracteres Unicode invisibles: zero-width spaces (U+200B), marcas RTL (U+200F), non-breaking spaces (U+00A0) en el input pasan un isdigit() naive o rompen el strip de guiones.
  • CUIT pegado a texto en el mismo campo: inputs del tipo "CUIT: 20-12345678-6" o "CUIT20123456786-fecha" requieren extracción antes de validar.
  • Validación de prefijo + dígito base consistente: algunos CUITs tienen prefijo de empresa (30) con un DNI base que no existe o viceversa. El checksum pasa, pero el CUIT no fue emitido jamás.
  • Performance en batch de 100k+ CUITs: compilar la expresión regular una sola vez fuera del loop puede reducir el tiempo de validación en un orden de magnitud. El algoritmo en sí es O(1) pero el overhead de re-compilar regex por cada llamada acumula.
  • Encoding en sistemas legacy: CUITs que vienen de sistemas COBOL o AS/400 pueden llegar en EBCDIC o con padding de espacios fijos. Truncar sin verificar la longitud real produce falsos negativos.
  • CUIT como entero: sistemas que almacenan el CUIT como número entero pierden el cero inicial del prefijo cuando el CUIT empieza con 0 (aunque en la práctica actual los prefijos no empiezan con 0, bases históricas pueden tener este problema).
  • Doble guion o guion al final: inputs como 20--12345678-6 o 20-12345678- que pasan un replace simple pero producen strings de longitud incorrecta.
  • CUIT con letras (error de tipeo): el carácter O confundido con 0, la I con 1 — en sistemas donde el usuario tipea a mano. Sin normalización explícita, el check de isdigit falla sin mensaje útil.

¿Querés saltarte todo esto?

Manejar todos estos edge cases en producción cuesta semanas de testing y mantenimiento permanente conforme cambian las reglas regulatorias. La API de Normadata maneja todo lo de arriba — incluyendo los casos que ni listamos aquí — con una sola llamada REST.

Fuentes

Especificación técnica AFIP (documentación pública del algoritmo Mod-11 para CUIT/CUIL). El algoritmo es de conocimiento público y ha sido implementado por múltiples organismos e integraciones desde los años 90.