Panel del prototipo de integración Veri*Factu con la AEAT

Veri*Factu es el sistema antifraude de la AEAT (RD 1007/2023) que obliga a los sistemas de facturación a registrar cada factura con una huella encadenada e inalterable y, en modo Veri*Factu, a remitirla a Hacienda en tiempo real. Este prototipo es una integración directa en PHP puro con el servicio web RegFactuSistemaFacturacion de la AEAT, sin librerías de terceros ni pasarelas intermedias: habla por SOAP sobre HTTPS con autenticación mutua (mTLS) usando el certificado digital del obligado, tanto en preproducción (pruebas) como en producción.

El núcleo resuelve las tres piezas que hacen funcionar Veri*Factu: el cálculo de la huella SHA-256 según el algoritmo oficial (orden de campos fijo, resultado en hexadecimal mayúsculas), el encadenamiento de cada factura con la huella de la anterior, y la construcción manual del sobre SOAP con los namespaces del esquema oficial. Además interpreta la respuesta de la AEAT (estado del envío, CSV, errores por registro), genera la URL del QR de cotejo que debe imprimirse en la factura, soporta anulaciones y rectificativas, y permite consultar los registros ya presentados. Una decisión de arquitectura que documenta el propio README: en modo Veri*Factu no hace falta firmar cada registro con XAdES, porque la integridad la garantizan la huella encadenada y el canal autenticado por certificado.

Es un prototipo de referencia, no un SIF certificado. Incluye una interfaz web bloqueada al entorno de pruebas que se comporta como un sistema de facturación real (persiste facturas y auditoría de envíos en SQLite), pensada para entender y validar el flujo antes de dar el salto a producción. El README detalla con honestidad las limitaciones: la validación contra el XSD oficial, los registros de evento, la declaración responsable del fabricante y la robustez (reintentos, idempotencia, concurrencia) quedan como trabajo previo a un uso real.

  1. Composición de la factura y desglose de IVA Se construye un RegistroAlta con la identificación de la factura (NIF emisor, número/serie, fecha de expedición), el tipo (F1 completa, F2 simplificada, F3 sustitutiva, R1-R5 rectificativa) y una o varias líneas de desglose. El desglose no es una lista de productos: agrupa la base imponible por tipo impositivo y calificación (sujeta S1/S2, no sujeta N1/N2 o exenta E1-E6), con un máximo de 12 líneas. La interfaz calcula sola las cuotas, la CuotaTotal y el ImporteTotal, y el modelo valida la coherencia de totales con tolerancia de un céntimo.
  2. Encadenamiento con la factura anterior Antes de generar la huella, el sistema toma el último registro efectivamente aceptado por la AEAT. En la interfaz web la fuente de verdad es SQLite (Repository::ultimoRegistrado, que solo cuenta los estados de registro Correcto y AceptadoConErrores), de modo que un envío rechazado no rompe la cadena; los ejemplos de consola usan en su lugar la clase Cadena sobre un fichero JSON. Si no hay registro previo, la factura se marca como PrimerRegistro; si lo hay, hereda emisor, número/serie, fecha y huella del anterior.
  3. Cálculo de la huella SHA-256 oficial La clase Hash concatena los pares clave=valor en el orden exacto que define la AEAT (IDEmisorFactura, NumSerieFactura, FechaExpedicionFactura, TipoFactura, CuotaTotal, ImporteTotal, Huella anterior, FechaHoraHusoGenRegistro), unidos por '&', y aplica SHA-256 en hexadecimal mayúsculas. En la primera factura el campo Huella va vacío. Las anulaciones usan su propio orden de campos (los datos de la factura anulada, la huella anterior y la fecha/hora de generación).
  4. Construcción del sobre SOAP XmlBuilder genera el XML con DOMDocument, sin SoapClient, respetando los namespaces (SuministroLR.xsd, SuministroInformacion.xsd) y el orden de campos del esquema oficial: cabecera con el obligado a la emisión, IDFactura, tipo, bloque de rectificativa cuando aplica, destinatario (NIF español o IDOtro para extranjeros), desglose, totales, bloque de Encadenamiento, identificación del SistemaInformatico, fecha/hora de generación, tipo de huella y huella.
  5. Envío mTLS a la AEAT AeatClient extrae el certificado y la clave privada del .pfx con openssl_pkcs12_read, los vuelca a ficheros PEM temporales con permisos 0600, y hace un POST cURL al endpoint VerifactuSOAP con autenticación mutua (CURLOPT_SSLCERT/SSLKEY), verificación de peer y host activadas, timeout configurable y borrado de los ficheros temporales en el bloque finally. No usa librerías SOAP externas.
  6. Interpretación de la respuesta y persistencia ResponseParser lee la respuesta con XPath usando local-name() para ser inmune a los prefijos de namespace, detecta SOAP Fault, y extrae el EstadoEnvio, el CSV y el detalle de errores por registro (estado por línea, código y descripción de error). La interfaz guarda la factura (con su huella, QR y estado) y registra en la tabla de auditoría el XML enviado, la respuesta completa y el resultado. Solo si la AEAT acepta se actualiza el eslabón de la cadena y la factura referenciada (origen rectificada o factura anulada).

Alta de factura en Veri*Factu

Genera el registro de alta con su huella encadenada y lo remite a la AEAT en tiempo real. Soporta F1 (completa, exige destinatario) y F2 (simplificada, sin destinatario).

Huella SHA-256 según el algoritmo oficial

Calcula la huella con el orden de campos exacto que exige la AEAT, en hexadecimal mayúsculas, tanto para altas como para anulaciones.

Encadenamiento inalterable

Cada factura incorpora la huella de la anterior; el eslabón solo avanza si la AEAT acepta el envío, leyendo el último registro válido desde la base de datos (o desde un fichero JSON en los ejemplos de consola).

Cliente SOAP mTLS sin dependencias

Construye el sobre SOAP a mano y lo envía con cURL y autenticación mutua usando el .pfx del obligado, extrayendo certificado y clave con OpenSSL. Sin SoapClient ni paquetes externos.

Parseo robusto de la respuesta

Interpreta el EstadoEnvio, el CSV y los errores por línea mediante XPath con local-name(), inmune a los prefijos de namespace, y detecta SOAP Fault.

Generación de la URL del QR de cotejo

Devuelve la URL al servicio ValidarQR de la AEAT (con NIF, número/serie, fecha e importe) lista para codificar en el QR de la factura, más la leyenda VERI*FACTU. No renderiza la imagen: deja ese paso a cualquier codificador de QR.

Anulación de facturas

Genera y envía el registro de anulación, con guardas que impiden anular una factura no registrada o ya anulada.

Rectificativas R1-R5

Soporta facturas rectificativas por sustitución (S, con base y cuota rectificadas) o por diferencias (I), referenciando la factura origen y marcándola como rectificada cuando la AEAT acepta el envío.

Consulta de registros presentados

Recupera de la AEAT (ConsultaFactuSistemaFacturacion) las facturas ya presentadas por ejercicio y periodo, con datos de presentación (NIF del presentador, fecha, id de petición), estado, huella, NIF de representante y paginación; permite elegir test o producción por ser una operación de solo lectura.

Interfaz web de pruebas con persistencia

Front controller con vistas para crear, previsualizar, enviar, anular, consultar y revisar el historial; guarda facturas y auditoría de cada envío en SQLite, con token CSRF y entorno bloqueado a preproducción.

  • PHP 8.1+: Lenguaje de toda la integración, en código puro con clases tipadas (strict_types) y un autoloader PSR-4 propio, sin Composer ni framework.
  • ext-openssl: Abre el certificado PKCS#12 (.pfx/.p12) con openssl_pkcs12_read y extrae certificado y clave privada para autenticar el envío; también expone el error de OpenSSL para diagnóstico cuando falla la contraseña.
  • ext-curl: Realiza el POST SOAP a la AEAT con autenticación mutua mTLS (CURLOPT_SSLCERT/SSLKEY), verificación de peer/host, timeouts y captura del código HTTP y de los errores de conexión.
  • ext-dom (DOMDocument): Construye los sobres SOAP de alta, anulación y consulta a mano, respetando namespaces y el orden de campos del esquema oficial de la AEAT.
  • ext-hash (SHA-256): Calcula la huella de cada registro según el algoritmo oficial, en hexadecimal mayúsculas, base del encadenamiento inalterable.
  • DOMXPath con local-name(): Parsea las respuestas de la AEAT (estado, CSV, errores, datos de consulta) sin depender de los prefijos de namespace que devuelva el servicio.
  • SQLite (PDO): Persiste las facturas y la auditoría de cada envío (XML enviado, respuesta completa, estado, CSV) en la interfaz web; es la fuente de verdad del encadenamiento y soporta el ciclo de vida (anulada/rectificada) con migraciones idempotentes.
  • SOAP (RegFactuSistemaFacturacion): Protocolo del servicio web de la AEAT para el suministro de altas y anulaciones; el mismo endpoint (VerifactuSOAP) sirve también la consulta cambiando el elemento raíz.
  • Certificado FNMT en PKCS#12: Identifica al obligado tributario (persona física, representante de persona jurídica o sello de entidad) y autentica el canal TLS hacia la AEAT.
  • Servicio QR ValidarQR de la AEAT: Destino de la URL de cotejo que se codifica en el QR impreso en la factura para verificarla en la sede electrónica.
  • Software de facturación o ERP propio de una pyme que necesita cumplir Veri*Factu enviando sus facturas a la AEAT sin contratar una pasarela externa ni pagar por factura.
  • Asesoría o gestoría que presenta facturas en nombre de varios clientes y necesita saber con qué NIF presentador y representante se envió cada una, usando la consulta de registros presentados.
  • Autónomo o sociedad que quiere validar en preproducción, con su propio certificado, que sus facturas pasan el control de la AEAT (estado Correcto + CSV) antes de operar en producción.
  • Equipo de desarrollo que evalúa el coste real de integrar Veri*Factu en su producto y necesita un referente PHP claro del algoritmo de huella, el encadenamiento y el sobre SOAP.
  • Negocio que emite tickets simplificados (F2) y facturas completas B2B (F1) y necesita gestionar también anulaciones y rectificativas con trazabilidad del ciclo de vida de cada documento.
  • Auditoría interna o departamento fiscal que requiere conservar, por cada factura, la huella, el QR, el XML enviado y la respuesta literal de la AEAT como evidencia.
  • Integración directa con un servicio web SOAP de la Administración usando autenticación mutua mTLS con certificado PKCS#12, sin librerías intermedias.
  • Implementación fiel de un algoritmo normativo (huella SHA-256 encadenada) con el orden de campos exacto exigido por la AEAT.
  • Construcción y parseo de XML namespaced de bajo nivel (DOMDocument + XPath con local-name()) resistente a los prefijos del servicio remoto.
  • Diseño de la cadena de integridad con la base de datos como fuente de verdad, de forma que un rechazo no corrompe el encadenamiento.
  • Manejo seguro de material criptográfico sensible: extracción del .pfx a ficheros temporales con permisos restringidos y borrado garantizado tras el envío.
  • Criterio de ingeniería honesto sobre el alcance: separa lo verificado (el núcleo) de lo pendiente para producción (validación XSD, registros de evento, reintentos, concurrencia).

Capturas con datos de demostración. Los certificados y datos fiscales reales nunca se publican.

De prototipo a producción

Si algo de esto encaja con un problema real de tu negocio, lo convertimos en una solución mantenible y con control total.

Hablemos de tu proyecto

Diagnóstico gratuito — Detecta dónde se pierden horas y qué automatización tiene más retorno

Pedir diagnóstico