Blog

PDF/A y Factur-X explicados para ingenieros (sin la jerga legal)

Qué restringen realmente los perfiles PDF/A, por qué Factur-X / Facturae son obligatorios en España desde 2026, y el pipeline más pequeño práctico para emitir desde un renderizador JSON.

Si eres ingeniero al que acaban de decir «las facturas tienen que ser PDF/A-3 con Factur-X para el próximo trimestre», y tu único contexto es que alguien en legal pronunció esas palabras, este post es para ti.

Cortamos el tono de los documentos de estandarización y explicamos qué restringen realmente estos perfiles, por qué los gobiernos empezaron a obligarlos y el pipeline más pequeño práctico para emitir un PDF conforme desde un renderizador de datos estructurados.

PDF/A en dos párrafos

PDF es un formato flexible. Demasiado flexible — la misma especificación PDF te permite embeber JavaScript, enlazar a recursos externos que pueden no existir en 50 años, cifrar contenido con criptografía reversible, referenciar fuentes externas, y cien cosas más que vuelven un documento no autocontenido.

PDF/A («A» de Archival) es un perfil de PDF que prohíbe las partes que impedirían que el documento se renderizara idénticamente en 50 años. Las reglas de alto nivel:

  • Todas las fuentes deben estar embebidas.
  • Sin JavaScript, sin enlaces externos, sin audio/video.
  • Sin cifrado.
  • Toda transparencia debe ser aplanada o soportada por la versión del perfil.
  • Los colores deben ser independientes del dispositivo (perfil ICC requerido).
  • Todo el contenido debe estar en el archivo — sin referencias que dependan de la red.

Hay varias versiones, cada una añadiendo tolerancia para funciones más nuevas:

PerfilAñoQué añade
PDF/A-1b2005Línea base original — el más estricto
PDF/A-2b2011Permite JPEG2000, transparencia, capas
PDF/A-3b2012Permite adjuntos de archivo arbitrarios (la fundación de Factur-X)
PDF/A-42020Base ISO 32000-2 (PDF 2.0), niveles de conformidad simplificados

El sufijo «b» significa conformidad «basic» (fidelidad visual). También existen variantes «u» (mapeadas Unicode) y «a» (etiquetadas para accesibilidad) — para la mayoría de workflows factura/recibo, «b» es lo que quieres, porque el archivado fiscal se preocupa por reproducibilidad visual, no semántica para lectores de pantalla.

Conclusión práctica: si tu renderizador dice que soporta PDF/A-3b, debería ser un único flag de configuración ({ profile: "PDF/A-3b" } o equivalente). Si tienes que ejecutar una segunda herramienta (Ghostscript, qpdf, Acrobat) para convertir después, eso es un hueco de workflow para considerar en tus ops.

Por qué PDF/A-3 importa específicamente: es el portador de las facturas electrónicas

PDF/A-3 añadió una capacidad que resultó cambiando el mundo: adjuntos de archivo arbitrarios dentro del PDF.

Suena aburrido. No lo es. Es la fundación técnica completa de los mandatos de factura electrónica desplegándose en Europa ahora mismo.

La arquitectura: un único archivo PDF que es tanto

  1. Una factura legible por humanos (layout visual, totales, branding) — la parte que el humano lee.
  2. Una factura XML legible por máquina — la parte que el software de la autoridad fiscal parsea.

Ambas dentro de un archivo, ambas representando la misma factura, y el wrapper PDF/A-3 garantiza que el archivo seguirá siendo parseable en décadas.

Los dos formatos XML principales:

  • Factur-X (Francia) — perfil XML basado en UN/CEFACT Cross Industry Invoice
  • ZUGFeRD (Alemania) — sustancialmente idéntico a Factur-X (los dos estándares se fusionaron técnicamente en 2018)
  • EN 16931 — la norma europea a la que ambas implementaciones se conforman
  • Facturae (España) — formato XML español que también se basa en EN 16931 cuando se exporta para interoperabilidad

Para la mayoría de workflows, «Factur-X» y «ZUGFeRD» son términos intercambiables — comparten un esquema, comparten el mecanismo de embedding, y un único PDF conforme con uno generalmente lo es con el otro.

Qué es obligatorio, dónde, cuándo

Una instantánea no exhaustiva para ingenieros planeando rollouts Q2/Q3 2026:

PaísEstadoFormato requerido
EspañaEmisión obligatoria desde 2026 (B2B); reglamento Crea y Crece + ley antifraudeFacturae vía FACe; XML EN 16931
AlemaniaB2B obligatorio para recepción desde 2025-01-01; emisión desde 2027EN 16931 (ZUGFeRD / Factur-X / XRechnung)
FranciaEmisión obligatoria para grandes empresas 2026-09; PYMES 2027-09Factur-X vía Chorus Pro
ItaliaB2B obligatorio desde 2019FatturaPA vía SDI
PoloniaObligatorio desde 2024-07KSeF
BélgicaObligatorio desde 2026-01Peppol BIS 3

El patrón: cada estado miembro de la UE está implementando alguna variante de e-facturación conforme EN 16931 en una timeline 2024–2027. Si tus clientes operan en cualquiera de estos mercados, tu generador PDF necesitará emitir XML adjunto junto a la factura visual.

Para equipos en España específicamente: la Ley Crea y Crece (aprobada 2022) más el Reglamento de factura electrónica (2024) son la base legal. En la práctica, esto significa que toda empresa española B2B debe, a partir de 2026, emitir facturas electrónicas estructuradas — no solo PDFs como imágenes, sino archivos PDF/A-3 con XML Facturae integrado, enviados vía FACe (la plataforma pública) o Plataformas de Facturación Electrónica privadas autorizadas.

El pipeline más pequeño práctico

Olvida lo que prescriben los documentos de estandarización. Aquí la vista de ingeniería:

   ┌─────────────────────┐
   │  Datos de tu        │  (ya un objeto JSON en algún lugar)
   │      factura        │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Construir XML       │  (mapeo determinístico; libs probadas existen)
   │     EN 16931        │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Renderizar PDF/A-3b │
   │ + adjuntar XML      │  (una llamada API a gPdf — o dos pasos en otros)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │  Entregar a         │
   │  FACe / Chorus Pro/ │
   │  SDI / Peppol / etc │
   └─────────────────────┘

Los dos pasos no triviales:

Paso 1: construir el XML

Esto es molesto pero mecánico. Mapea los datos de tu factura (líneas, impuestos, totales, partes) a nombres de campo XML EN 16931. Varias librerías Java/Node/Python lo hacen por ti — busca «factur-x library» o «facturae library» en tu lenguaje. No lo escribas desde cero a menos que realmente disfrutes especificaciones de esquema XML.

Paso 2: renderizar PDF/A-3 y adjuntar el XML

Aquí importa la elección del renderizador.

Sin soporte integrado: renderizas un PDF ordinario, luego post-procesas con una herramienta que convierte a PDF/A-3 y adjunta el XML como archivo embebido. Stacks comunes: Ghostscript + qpdf, o una herramienta de pago como Aspose. Dos pasos extra, dos puntos de fallo extra, y debes asegurar que el post-procesamiento no derive el layout visual.

Con soporte integrado (el enfoque de gPdf): una llamada.

curl -X POST https://gpdf.com/api/v1/e-invoice/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "document": {
      "pages": [{ "size": "a4", "elements": [...] }]
    },
    "einvoice": {
      "format": "factur-x",
      "profile": "BASIC",
      "xml": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
    }
  }' \
  --output factura-con-factur-x.pdf

Eso es todo el pipeline. El renderizador emite PDF/A-3b, adjunta tu XML como factur-x.xml (o zugferd-invoice.xml, ambos reconocidos por cada consumidor), y devuelve los bytes.

Trampas comunes

Algunas cosas que la gente aprende por las malas:

«PDF/A» y «con fuentes conformes a PDF/A» no son lo mismo

Un archivo PDF/A-3 requiere que todas las fuentes estén embebidas con cobertura completa de glifos usados. Si tu factura tiene un nombre de cliente extranjero y el renderizador hace fallback a una fuente que no es completamente embebible, las herramientas de validación lo rechazarán. Verifica que tu renderizador embeba fuentes CJK en modo PDF/A — muchos no lo hacen por defecto.

Visual + XML deben coincidir

La factura XML y la factura visual se supone que representan la misma factura. Los auditores fiscales las van a diff. Si tu código emite XML con total: 119,00 y el PDF visual muestra Total: 120,00 (por un bug de redondeo o una plantilla obsoleta), tienes una discrepancia fiscal en el archivo. Genera ambas desde la misma fuente de verdad, idealmente en el mismo path de código.

Niveles de «perfil» en EN 16931

Factur-X tiene perfiles: MINIMUM, BASIC, EN 16931, EXTENDED. Difieren en cuántos datos están en el XML. Usa BASIC a menos que tu cliente requiera específicamente más — cubre códigos fiscales, líneas, partes, totales, lo que es suficiente para ~95 % de la facturación B2B.

Validación antes de envío

Valida siempre el PDF generado contra un validador PDF/A (veraPDF es el estándar open-source) y valida el XML contra el esquema EN 16931 antes de enviar a la autoridad fiscal. Envíos fallidos a FACe / Chorus Pro / SDI cuentan contra tus métricas de fiabilidad con el regulador.

TL;DR

PDF/A es un perfil de documento autocontenido. PDF/A-3 te permite adjuntar archivos. Factur-X / ZUGFeRD es «un XML EN 16931 adjunto dentro de un PDF/A-3». Los mandatos de factura electrónica a través de la UE hacen de esta combinación el formato de facto B2B para 2025–2027.

Si tu renderizador trata PDF/A-3 + Factur-X como un único flag de configuración, la migración es mecánica. Si no, estás construyendo un pipeline de ops multi-paso. El /api/v1/e-invoice/render de gPdf es la versión single-flag — la referencia API tiene el esquema completo, o prueba un render de muestra en el Playground.