Guía de Integración VeriFactu para PHP (Completa)

Resumen: Esta guía documenta la integración técnica del adaptador "Micro Server" en entornos PHP (Web y CLI). Permite delegar la complejidad criptográfica y de comunicación con la AEAT a un backend intermedio, diseñado para cumplir con la normativa VeriFactu de forma robusta y sencilla.


1. Arquitectura del Motor (Engine PHP)

El motor ha sido diseñado bajo la filosofía "Drop-in": un solo archivo .php sin dependencias de Composer ni frameworks externos, garantizando compatibilidad con hostings compartidos, CMS (WordPress, PrestaShop) y aplicaciones legacy.

Componentes Principales

El núcleo consta de dos archivos esenciales que deben copiarse a su proyecto:

  1. vf_engine.php (El Motor)

  2. config.ini (Configuración)

1.1. Responsabilidad Criptográfica (Certificados AEAT vs HTTPS)

Es de vital importancia distinguir entre los certificados de la AEAT y la comunicación SSL de la API:

Máquina de Estados Implícita

El sistema gestiona el ciclo de vida de la factura en tres fases: 1. INGESTA: Envío del JSON de la factura al Backend. El backend la guarda inmediatamente (buffer). 2. POLLING: Consulta periódica de la cola de "Pendientes" (facturas ya procesadas por la AEAT) esperando confirmación. 3. ACK: Confirmación de recepción por parte del ERP/Web tras guardar la Huella y la URL del QR.


2. Configuración del JSON (Altas, Subsanaciones y Anulaciones)

No encontrará en esta guía una documentación exhaustiva sobre cómo construir el JSON campo a campo. ¡No es necesario!

El Panel de Administración Web del Micro Server (sección Envíos) incluye una herramienta de Generación de Payloads interactiva diseñada específicamente para desarrolladores.

Flujo de Diseño Recomendado:

  1. Acceda al Panel Web del Micro Server.
  2. Seleccione el tipo de operación (Alta, Anulación, Rectificativa...).
  3. Rellene los datos en el formulario visual.
  4. Copie el JSON generado y validado directamente a su código PHP.

Nota sobre metadata: El esquema JSON exige un bloque metadata en la raíz. Aunque actualmente su contenido es ignorado, debe estar presente para pasar la validación del esquema.


3. Flujo de Trabajo Típico

El Backend actúa como un buffer inteligente. Su aplicación PHP no habla con la AEAT directamente; habla con este Micro Server.

Paso 1: Ingesta (ingestaJson)

Su aplicación genera un array o JSON con los datos de la factura y lo envía.

$res = $vf->ingestaJson($datosFactura);
if ($res['ok']) {
    // Factura aceptada en el sistema. ID Tracking: $res['tracking']['cab_num_secuencia']
}

Paso 2: Espera Activa / Polling (getPendientes)

El ERP o un proceso Cron debe preguntar periódicamente al endpoint de pendientes.

$res = $vf->getPendientes("B12345678", 50);

Paso 3: Confirmación (ackIndice)

Una vez que su sistema ha recuperado los datos finales (QR y Huella): 1. Guárdelos en su base de datos local asociados a la factura. 2. Envíe un ACK al Backend indicando el indice_log. 3. El Backend marca esa operación como "Entregada" y la saca de la cola.


4. Reglas de Negocio Críticas

El sistema implementa lógica avanzada para manejar situaciones complejas:

1. Antelación (Envío Previo)

Las facturas pueden enviarse con fecha de emisión futura o anterior. El backend las custodiará hasta que sean procesadas.

2. Modificación (Pre-AEAT) - "Corregir antes de enviar"

Si envía una factura (mismo NIF, Serie y Número) y esta aún no ha sido procesada por la AEAT (sigue en cola interna): * La nueva versión SOBRESCRIBE a la anterior. * Esto permite corregir errores (ej: olvidar el IVA) si se detectan rápido, sin dejar rastro de la versión errónea en la AEAT.

3. Subsanación (Post-AEAT) - "Rectificar después de enviar"

Si envía una factura que YA fue procesada y aceptada por la AEAT: * Si el sistema detecta cambios, intentará enviarla como una Subsanación (si la configuración lo permite). * En caso contrario, la AEAT devolverá un error indicando que la factura ya existe, forzando a realizar una factura rectificativa (con nueva serie/número).

4. Validaciones Inmediatas

La ingesta devolverá error (HTTP 4xx/5xx) si detecta: * Errores de sintaxis JSON. * Incoherencias matemáticas graves (Total != Base + Cuota). * Falta de campos obligatorios (NIF, Fecha, Totales).


5. Visualización de QR en PHP

A diferencia de entornos de escritorio, en PHP la visualización es trivial. El campo url_qr_verifactu devuelto en el Paso 2 es una URL pública de la AEAT.

En Sitio Web / HTML

Simplemente incruste la imagen generada por la AEAT (o use una librería JS como qrcode.js):

<!-- Opción A: Enlace directo (La AEAT genera el PDF/Imagen) -->
<a href="<?php echo $item['url_qr_verifactu']; ?>" target="_blank">Ver QR VeriFactu</a>

<!-- Opción B: Generar QR en el navegador -->
<div id="qrcode"></div>
<script>
    new QRCode(document.getElementById("qrcode"), "<?php echo $item['url_qr_verifactu']; ?>");
</script>

6. Configuración (config.ini) y Autenticación (API Key)

Para garantizar la seguridad en un entorno Multi-Tenant, el Micro Server puede exigir una API Key (Token) para autorizar todas las peticiones y restringir el acceso a la información de los emisores (RBAC).

El motor PHP se encarga automáticamente de inyectar las cabeceras HTTP de seguridad (X-API-Key y X-Verifactu-Emisor) si se configuran correctamente en su archivo config.ini:

[api]
; URL del VeriFactu Micro Server
base_url=http://localhost:8000
; Timeout para cURL
timeout_sec=30
; Token de seguridad (API Key). Si el backend exige autenticación (require_auth=true), este campo es OBLIGATORIO.
token=mi_clave_api_secreta_123
; Verificar SSL (false para desarrollo local inseguro, true para producción)
ssl_verify=true

[demo]
; NIF del emisor asociado a esta instancia. El API Key debe tener permisos sobre este NIF.
nif_emisor=B12345678

6.1. Autenticación y Seguridad Multi-Tenant (RBAC)

Si la opción require_auth=True está activada en el backend, la API exigirá dos elementos de seguridad obligatorios que vf_engine.php envía por defecto:

  1. X-API-Key (Token): Identifica al usuario o integración ERP.
  2. X-Verifactu-Emisor (NIF): Declara el NIF sobre el que se va a operar. El servidor comprueba si la API Key facilitada tiene permisos concedidos explícitamente sobre este NIF.

Prevención de Suplantación en la Ingesta: Como medida de máxima seguridad, durante una operación de Ingesta, el servidor abre el JSON enviado y verifica que el campo cabecera.emisor coincida exactamente con el NIF para el que el usuario se ha autenticado. Si un usuario intenta enviar o consultar facturas camuflando un NIF ajeno, la operación se abortará inmediatamente devolviendo un error HTTP 403 Forbidden. Lo mismo ocurrirá si intenta consultar facturas pendientes de otro emisor.

7. Solución de Problemas (Troubleshooting)

Error cURL SSL (Certificado auto-firmado)

Timeout en "Pendientes"

HTTP 422 - Regla de Negocio


8. Métodos Auxiliares (Nuevos)

checkStatus($nif, $serie, $num)

Consulta ligera para saber si una factura concreta ya se procesó, sin traer toda la lista de pendientes. Útil para interfaces "AJAX" que muestran el estado en tiempo real.

getEstadoFactura($nif, $num, $serie)

Devuelve la traza completa (logs) de una factura. Útil para depurar por qué una factura ha sido rechazada por la AEAT, mostrando el mensaje de error exacto devuelto por Hacienda.