Actualización de catálogos CFDI (junio 2026, c_NumPedimentoAduana): tu código no cambia, pero tu pipeline sí — Cesar Ayala
← Todos los artículos

Actualización de catálogos CFDI (junio 2026, c_NumPedimentoAduana): tu código no cambia, pero tu pipeline sí

El 19 de junio de 2026 el SAT publicó una actualización de catálogos del CFDI 4.0 que agrega registros obligatorios a c_NumPedimentoAduana, el catálogo de pedimentos aduaneros usado en facturación de comercio exterior. Los esquemas XSD NO se modificaron, así que tu código de integración no cambia. Solo necesitas el catálogo actualizado, pero si tu pipeline hardcodea catálogos, tu PAC empezará a rechazar en silencio.

¿Qué cambió el 19 de junio de 2026?

El SAT publicó una actualización de catálogos del CFDI 4.0 con efecto a partir del 19 de junio de 2026. La actualización agrega nuevos registros obligatorios al catálogo c_NumPedimentoAduana, el catálogo de pedimentos aduaneros que usas cuando facturas comercio exterior (importación y exportación). La nota de LLB reporta 15 nuevos registros; confirma el conteo vigente contra el SAT, porque puede seguir creciendo.

Lo importante para nosotros, los que mantenemos un pipeline de timbrado: esto ya está vigente. No es un aviso de “para el próximo año”. Desde esa fecha, los nuevos registros son obligatorios en la validación, y tu PAC valida contra ellos antes de timbrar. Si mandas un CFDI de comercio exterior con un valor de pedimento que ya no embona con el catálogo vigente, el timbrado se rechaza.

Y aquí va la buena noticia, la que casi nadie te dice de entrada: tu código no cambia. Lo que cambió es dato, no estructura. Pero si tu pipeline hardcodea catálogos, eso te va a morder en producción. Vamos por partes.

Fuentes oficiales para confirmar la actualización: SAT y la nota de LLB Solutions sobre la actualización CFDI 4.0 2026. Como siempre con temas regulados: confirma la regla vigente al momento en que leas esto, porque los catálogos se mueven.

Fecha19 de junio de 2026 (vigente; confirma la regla actual)
Qué cambióNuevos registros obligatorios en c_NumPedimentoAduana (LLB reporta 15)
AlcanceFacturación de comercio exterior (importación / exportación)
XSDNO se modificó — sin nuevos atributos ni nodos
Tu acciónRefrescar el catálogo; tu código de integración no cambia

Por qué tu código de integración no cambia

Esta es la parte que ahorra horas de trabajo si la entiendes bien. Los esquemas XSD del CFDI no se tocaron. La estructura técnica del comprobante sigue igual: mismos nodos, mismos atributos, misma versión de esquema. No hay un atributo nuevo que serializar, no hay un nodo que agregar, no hay un binding que regenerar.

Cuando el XSD no cambia, tu capa de código se queda intacta:

  • Tus builders de XML siguen produciendo el mismo árbol.
  • Tu serialización no cambia.
  • Tu validación contra el XSD (la estructural) sigue pasando igual.
  • No hay redeploy obligado por estructura.

Lo único que necesitas es el catálogo c_NumPedimentoAduana actualizado, cargado en tu pipeline, para que tu validación de valores use la lista vigente. Es un refresco de datos. Si tu pipeline ya carga catálogos desde una fuente externa y no desde constantes en el código, este cambio es casi un no-evento: actualizas el dataset y listo.

Si te suena a poco, es porque debería serlo. El problema no es este cambio; el problema es cómo está construido tu pipeline. Ese es el verdadero tema de este post.

Refresco de datos vs cambio de código: saber la diferencia

Si automatizas CFDI, vale oro tener este modelo mental para clasificar rápido cada boletín del SAT. Hay dos tipos de cambios y piden cosas distintas:

Cambio de XSD / esquema — toca tu código. Aparece un atributo nuevo, un nodo nuevo, o sube la versión del complemento. Aquí sí: actualizas tus modelos, regeneras bindings, ajustas validadores, y rediseñas y redespliegas. Es trabajo de ingeniería real.

Cambio de catálogo — toca tus datos. Cambian los valores permitidos: se agregan, se quitan o se actualizan registros. Aquí no rediseñas nada; refrescas un dataset. Cero redeploy si tu arquitectura ya lo contempla.

La actualización de junio 2026 de c_NumPedimentoAduana cae firmemente en el segundo grupo. Son registros nuevos en una lista de valores permitidos. Punto.

Leer mal esto cuesta en los dos sentidos. Si lo tratas como cambio de código, pierdes tiempo de ingeniería rediseñando algo que no cambió. Si lo ignoras porque “no toca el código”, te olvidas del lado de datos y tu PAC empieza a rechazar en silencio. La clasificación correcta es la que te salva.

Lo que SÍ cambió (datos)

  • Nuevos registros obligatorios en c_NumPedimentoAduana
  • Es la lista de valores permitidos del pedimento
  • Se resuelve refrescando el catálogo en tu pipeline
  • Cero redeploy si no hardcodeas

Lo que NO cambió (código)

  • El XSD del CFDI 4.0 quedó intacto
  • Sin atributos nuevos, sin nodos nuevos
  • Sin bump de versión de esquema
  • Tus builders, serialización y validación estructural siguen igual

Por qué hardcodear catálogos rompe tu pipeline

Aquí es donde el detalle se vuelve concreto. Imagina que validas los inputs contra un catálogo c_NumPedimentoAduana que vive como una constante dentro de tu código, congelado el día que lo escribiste. Pasan dos cosas feas, según el caso:

  • Un valor de pedimento que ahora es válido según el SAT te parece inválido a ti, y tu propia validación lo rechaza antes de siquiera intentar timbrar. Frenas comprobantes buenos.
  • O al revés: usas un valor que tu constante todavía considera válido pero que el SAT ya retiró del catálogo. Tu validación local lo aprueba y el rechazo llega del lado del PAC.

Porque el PAC sí valida contra el catálogo vigente del SAT. Tu constante hardcodeada y el catálogo real se separan, y el PAC rechaza. Desde la perspectiva de tu app, muchas veces ese rechazo se siente “silencioso”: no es un error de tu código, es un timbrado que no se completó, en producción, sobre facturas reales de comercio exterior, justo en el momento en que tu cliente necesita el CFDI.

Los catálogos hardcodeados son constantes que el SAT muta por debajo de ti sin avisarte a tu repo. No las controlas tú. Por eso el arreglo no es parchar este update a mano y seguir; es cambiar cómo tu pipeline obtiene los catálogos. Si parchas a mano, vuelves a estar igual en la siguiente actualización.

Camino correcto: sincronizasCargas los catálogos vigentes → validas inputs contra ellos → timbras → el PAC acepta
Camino roto: hardcodeasValidas contra un catálogo viejo en código → mandas a timbrar → el PAC valida contra el vigente → rechazo silencioso
El punto de fallaLa separación entre tu constante congelada y el catálogo real del SAT
La diferenciaNo es tu código: es de dónde sale el dato del catálogo

Los catálogos del SAT cambian constantemente: este es el patrón

Que no se te quede esto como “el update de junio”. El verdadero aprendizaje es el patrón. c_NumPedimentoAduana por sí solo se ha actualizado en varias ocasiones durante 2026, en distintas fechas a lo largo del año (las bases de conocimiento de los PACs listan avisos fechados de “Actualización de Catálogos SAT / Información Aduanera” en febrero y marzo, entre otros). No fue un evento único: es un goteo constante. Confirma las fechas y versiones exactas contra el SAT al momento de leer, porque siguen moviéndose.

Y no es solo ese catálogo:

  • Carta Porte 3.1 trae sus propios catálogos que se actualizan por su cuenta. Si lo manejas, ya lo viviste — lo cubro en la guía de Carta Porte para desarrolladores.
  • La lista L_CNE —el padrón de permisos que publica la Comisión Nacional de Energía (CNE, antes CRE) y que el PAC valida antes de timbrar el complemento de Hidrocarburos— se actualiza a diario. Diario. Ojo: no es un catálogo del SAT sino de otra autoridad, lo que hace aún más obvio por qué hardcodearlo es suicida. Si la hardcodeas, estás perdido desde el día dos. Lo desgloso en la guía del complemento de Hidrocarburos.

El patrón es claro: trata los catálogos del SAT como datos que refrescas con un horario, no como constantes que hardcodeas. Esa sola decisión de diseño convierte cada actualización futura en un no-evento.

Nota de ingeniero, porque correctness es el valor aquí: confirma las reglas vigentes del SAT al momento de implementar, y los casos de borde fiscales (qué pedimento aplica, cómo clasificar una operación específica) déjaselos a tu contador o a compliance. Tú construyes el pipeline; ellos definen la regla fiscal.

Cómo hacer tu pipeline CFDI resistente a catálogos

Cuatro pasos. Esto es lo que aplico en los pipelines de timbrado que mantengo, y es lo mismo que endurece el pipeline de facturación CFDI automática con Stripe y Mercado Pago que ya tengas en producción.

Paso 1 — Job programado que sincroniza catálogos. Un cron que jala los catálogos más recientes desde tu PAC o desde el SAT, de forma automática. Diario para los que se mueven seguido (L_CNE), o según la cadencia que cada catálogo amerite.

Paso 2 — Valida contra el catálogo vigente ANTES de timbrar. Nunca contra una copia congelada en código. Validas el input contra el dataset que acabas de sincronizar.

Paso 3 — Alerta cuando suba la versión del catálogo. Para que un humano se entere de que aterrizó un cambio. No quieres descubrir la actualización por los rechazos del PAC.

Paso 4 — Nunca hardcodees valores de catálogo. Cárgalos siempre desde el dataset sincronizado. Esta es la regla que hace que las otras tres importen.

Un boceto ilustrativo, vendor-neutral. Ajusta el cliente del PAC y el almacenamiento a tu stack:

# Ilustrativo. Job programado de sincronización de catálogos SAT
# + validación contra el catálogo VIGENTE antes de timbrar.

import logging

logger = logging.getLogger("cfdi.catalogos")

class CatalogoError(Exception):
    """Define tu propia excepción de dominio."""
    pass

CATALOGOS = ["c_NumPedimentoAduana", "L_CNE"]  # los que tu flujo use

def sync_catalogos(pac_client, store):
    """Corre en un cron. Jala catálogos vigentes del PAC/SAT."""
    for nombre in CATALOGOS:
        remoto = pac_client.descargar_catalogo(nombre)   # versión + registros
        local = store.version_actual(nombre)
        if remoto.version != local:
            store.guardar(nombre, remoto.registros, remoto.version)
            # Paso 3: alerta cuando sube la versión
            alertar(f"Catálogo {nombre}: {local} -> {remoto.version}")
        else:
            logger.info("Catálogo %s sin cambios (%s)", nombre, local)

def validar_antes_de_timbrar(cfdi, store):
    """Paso 2: valida contra el catálogo VIGENTE, no contra constantes."""
    catalogo = store.cargar("c_NumPedimentoAduana")  # dato sincronizado
    valores_validos = catalogo.claves()
    for ped in cfdi.pedimentos:
        if ped.num_pedimento not in valores_validos:
            raise CatalogoError(
                f"Pedimento {ped.num_pedimento} no está en el catálogo "
                f"vigente {catalogo.version}. Re-sincroniza antes de timbrar."
            )
    return True

def alertar(mensaje):
    # Conéctalo a tu canal real (Slack, correo, PagerDuty).
    logger.warning("ALERTA CATÁLOGO: %s", mensaje)

Fíjate que en ningún lado hay una lista de pedimentos escrita a mano. El catálogo siempre sale del store que el cron mantiene fresco. Cuando el SAT publique el siguiente registro obligatorio, tu cron lo jala, tu alerta avisa, y tu validación ya usa el valor nuevo, sin tocar una línea de tu lógica de timbrado.

  1. Sincroniza con un horarioUn job jala los catálogos vigentes desde tu PAC o el SAT automáticamente
  2. Valida contra el vigenteRevisa cada input antes de timbrar y falla con un error claro
  3. Alerta al subir la versiónNotifica a un humano cuando cambie la versión o el hash del catálogo
  4. Nunca hardcodeesCarga los valores del catálogo desde el dataset sincronizado, siempre

Si quieres más guías de este tipo sobre fiscal y pagos, las junto en integraciones.

Preguntas frecuentes

¿Tengo que redesplegar mi código por la actualización de junio 2026? No. El XSD no cambió, así que tu código de integración no cambia. Solo refresca el dato del catálogo c_NumPedimentoAduana en tu pipeline.

¿Esto afecta todas mis facturas? Principalmente los CFDI de comercio exterior (importación y exportación) que llevan datos de pedimento. Si no facturas comercio exterior, este registro específico no te toca, pero el patrón de catálogos sí.

¿Cómo obtengo el catálogo nuevo? Sincronízalo desde tu PAC o desde el SAT. La mayoría de los PACs publican los catálogos actualizados; lo ideal es jalarlos con un job programado, no a mano.

¿Qué pasa si no hago nada? Tu PAC puede empezar a rechazar las solicitudes de timbrado afectadas una vez que los registros nuevos son obligatorios. En producción, sobre facturas reales, a veces de forma que se siente silenciosa desde tu app.

¿Esto es pregunta fiscal o de ingeniería? Ingeniería para el pipeline (sincronizar, validar, alertar). Los casos de borde fiscales — qué pedimento aplica, cómo clasificar una operación — déjaselos a un contador o a compliance.

La conclusión

El 19 de junio de 2026: nuevos registros obligatorios en c_NumPedimentoAduana, XSD intacto, código sin cambios, refresca el catálogo. Eso es todo lo que pide este update en concreto.

Pero el premio de verdad no es resolver este cambio: es construir un pipeline donde el siguiente cambio de catálogo sea un no-evento. Sincroniza con un horario, valida contra el catálogo vigente, alerta cuando suba la versión, y nunca hardcodees valores de catálogo. Hazlo una vez y dejas de perseguir cada boletín del SAT.

Y como siempre con SAT y Banxico: confirma las reglas vigentes al momento de implementar. Los catálogos son datos en movimiento, no constantes. Trátalos como tales y duermes tranquilo.