Verifactu en Node.js: guía de integración
Node.js es muy habitual en backends de pedidos, marketplaces y aplicaciones a medida. Y tiene una particularidad con Verifactu: es muy fácil hacer que funcione en pruebas y muy fácil que falle en producción, sobre todo por la concurrencia. Te cuento por dónde van los tiros.
Qué tiene que hacer tu backend
Con independencia de si usas Express, NestJS, Fastify o funciones sueltas, la capa de Verifactu hace cuatro cosas:
- Crea un registro por cada factura o abono.
- Calcula una huella que incluye la del registro anterior.
- Añade el QR al documento que recibe el cliente.
- Envía el registro a la AEAT (según la modalidad elegida).
Nada de esto exige reescribir tu aplicación. Se coloca donde se emite la factura.
El problema real: la concurrencia
Dos peticiones que facturan a la vez pueden leer el mismo «último registro» y crear dos registros que apuntan al mismo anterior. La cadena se rompe y, lo peor, no te enteras hasta que alguien la verifica.
Soluciones habituales:
- Bloqueo en base de datos sobre el último registro (por ejemplo
SELECT ... FOR UPDATEen PostgreSQL o MySQL). - Una cola de un solo consumidor que procese los registros de uno en uno.
- Una secuencia que garantice el orden.
Si tu aplicación escala en varias instancias, un bloqueo en memoria no sirve: el control debe estar en la base de datos o en un servicio común.
Idempotencia: no enviar dos veces lo mismo
En Node es normal trabajar con colas y reintentos. Y un reintento mal diseñado puede enviar dos veces el mismo registro a la AEAT. Cada envío debe ser idempotente: si ya se envió y fue aceptado, no se vuelve a enviar. Para eso se guarda el estado de cada registro (pendiente, enviado, aceptado, rechazado) y se consulta antes de actuar.
Envío desacoplado
La venta no debe esperar a la AEAT. El flujo correcto:
- Se emite la factura y se guarda el registro como pendiente.
- Un worker (BullMQ, un cron, un consumidor de cola…) lo recoge y lo envía.
- Si falla, reintenta con espera creciente.
- Cada intento queda registrado.
Si tu infraestructura es serverless, hay que cuidar que las funciones no se ejecuten dos veces sobre el mismo registro. Más sobre este diseño en cola de envíos a la AEAT.
El QR y el PDF
Si generas PDFs con Puppeteer, PDFKit o una librería similar, añadir el QR es un cambio pequeño. Lo importante es que el dato del QR salga del registro, no se reconstruya aparte, para que siempre coincidan.
Lo que suele fallar
Por experiencia:
- Facturas editadas directamente en la base de datos por una corrección rápida.
- Fechas con zonas horarias mal tratadas (la fecha de la factura importa).
- Redondeos distintos entre el cálculo de la tienda y el del registro.
- Procesos que facturan fuera del servicio principal.
Ninguno de estos problemas es de Node, son de orden. Pero Node, por su flexibilidad, los permite con facilidad.
Siguiente paso
Si tu backend está en Node.js y emite facturas, lo primero es mapear todos los puntos de emisión. Tienes el enfoque en Verifactu para Node.js, y el marco en adaptar un ERP propio a Verifactu. Si quieres que lo revisemos juntos, escríbeme.
Preguntas frecuentes
¿Sirve para NestJS y para Express? Sí. La capa se adapta a tu estructura, lo importante es el orden de la cadena de registros.
¿Qué base de datos necesito? La que ya uses, siempre que permita guardar factura y registro de forma consistente y controlar el orden.
¿Funciona en serverless? Se puede, pero hay que cuidar la idempotencia y el orden de los registros más que en un servidor tradicional.
Sigue leyendo
Cómo adaptar un ERP propio a Verifactu
Guía práctica para adaptar un ERP o programa de facturación propio a Verifactu: qué revisar primero, qué añadir y cómo hacerlo sin rehacer el sistema.
Cola de envíos a la AEAT con reintentos
Por qué enviar los registros de Verifactu desde una cola con reintentos y cómo diseñarla: estados, errores, tiempos de espera y qué hacer si la AEAT falla.
Qué es Verifactu y cómo funciona
Verifactu explicado sin jerga: qué registra tu software de facturación, qué es la huella y el QR, y qué ve la AEAT de cada factura que emites.