Arquitectura modular, ejemplos de código y guía técnica completa para integrar Verifactu en tu sistema, ya sea vía API REST o vía librería Java. Esta documentación es la capa técnica de Facturware - Verifactu API.
Solución enterprise modular multi-tenancy que permite integrar Verifactu en cualquier sistema rápidamente. Evita tener que implementar manualmente la lógica fiscal exigida por la AEAT lo cual puede llevar meses de desarrollo.
El sistema cubre todo el ciclo de vida de una factura:
Mapear factura → Elegir tipo → Validar → Generar hash → Firmar → Enviar AEAT → Obtener QR → Recibir estado → Subsanar o rectificar si procede
Permite trabajar con todos los tipos de factura definidos por la AEAT:
Dispone de una API de alto nivel con 6 métodos principales enfocados a todos los casos de uso posibles para operaciones con Verifactu:
Estos metodos estan perfectamente documentados, asi como los diferentes tipos de datos que suelen estar agrupados en ENUM con todas las variantes, se proveen ejemplos de uso basicos hasta los mas complejos. Normalmente un ERP se limitara a Crear, Anular, Rectificar y alguna vez Subsana. Aun que existen diferentes casos contemplados por el software por ejemplo: Importaciones (con parametros y regimenes especiales), Cafeteria que emite tickets F2 y posteriormente los transforma a F3, etc...
megafactur-core → Comunicacion SOAP AEAT + Operaciones bajo nivel (firma, hash, QR) | Librería Java pura (sin frameworks) ↑ megafactur-engine → API Java + persistencia + metodos operaciones alto nivel (Crear, Anular, Subsanar etc...) | Librería JOOQ + Flyway + HikariCP ↑ megafactur-server → API REST + dashboard | Microservicio Quarkus
Cada módulo es independiente y puede utilizarse de forma aislada según el caso de uso. El módulo server permite integración con cualquier tecnologia mediante REST.
Servidor autónomo basado en Quarkus que expone una API REST completa para operar con VERIFACTU.
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| `POST` | `/api/v1/{nif}/invoices` | Crear y registrar una nueva factura (F1, F2, F3, R1-R5) |
| `POST` | `/api/v1/{nif}/invoices/cancel` | Anular una factura |
| `POST` | `/api/v1/{nif}/invoices/correct` | Subsanar el registro enviado de una factura |
| `POST` | `/api/v1/{nif}/invoices/rectify` | Emitir factura rectificativa referenciando las originales |
| `POST` | `/api/v1/{nif}/invoices/convert-tickets` | Convertir uno o varios tickets F2 en una factura F3 con datos del cliente |
| `POST` | `/api/v1/{nif}/invoices/merge-breakdowns` | Obtener la fusión de desgloses de una o varias facturas |
| `POST` | `/api/v1/{nif}/invoices/check` | Validar los datos de una factura antes de enviarla |
| `GET` | `/api/v1/{nif}/invoices/{invoiceNumber}/status` | Consultar estado de la factura (local + AEAT) |
| `GET` | `/api/v1/{nif}/invoices/{invoiceNumber}/qr` | Obtener código QR de validación (imagen PNG) |
| `POST` | `/api/v1/{nif}/invoices/{invoiceNumber}/retry` | Reintento manual (solo TECHNICAL_ERROR y NOT_PROCESSED) |
El modulo implementa API FIRST, así que sencillamente descargando la especificación OPENAPI: http://localhost:8080/q/openapi Con Openapi generator y un cliente REST dependiendo de la tecnología se podrían generar modelos e interfaces fácilmente.
curl -X POST http://localhost:8080/api/v1/B72877814/invoices \
-H "X-API-Key: tu-clave-secreta-1" \
-H "Content-Type: application/json" \
-d '{
"invoiceNumber": "FACT-2024-001",
"issueDate": "2024-01-15",
"invoiceType": "F1",
"totalAmount": 1210.00,
"taxAmount": 210.00,
"issuerTaxId": "B72877814",
"issuerName": "Empresa Demo S.L.",
"operationDescription": "Servicios de consultoría",
"breakdowns": [
{
"claveRegimen": "01",
"calificacionOperacion": "S1",
"taxRate": 21.0,
"baseAmount": 1000.00,
"taxAmount": 210.00
}
]
}'
Diseño como microservicio Quarkus que puede integrase en sistema complejo, o sencillamente desplegar como artefacto java,
your-app/ ├── megafactur-server.jar ├── companies/ │ ├── B72877814/ │ │ ├── config.yml │ │ └── certificate.p12 │ └── A12345674/ │ ├── config.yml │ └── certificate.p12 └── application.properties # sobreescritura opcional
Existen ejemplos coherentes para cada operación, se dispone de schemas para que se pueda visualizar fácilmente los tipos de datos que se pueden mandar, posibilidades, combinaciones...
Este modulo tiene ademas un dashboard para visualizar todos los tenants, y para cada uno de ellos realizar operaciones de facturacion Las operaciones están bien definidas de manera que incluso los flujos y casos mas raros son intuitivos y sencillos de realizar
Librería de alto nivel diseñada para integrarse directamente en aplicaciones Java.
• Mediante fichero (YAML) • O programáticamente (builder) Debido a su diseño es compatible con cualquier Framework java EJB, Spring, Quarkus … ya que hace uso de librerias sin CDI por lo que sencillamente se importa como una librería,
<dependency>
<groupId>com.horus.megafactur</groupId>
<artifactId>megafactur-engine</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
Configuración mediante YAML:
apiKey: ${COMPANY_API_KEY} # API key por empresa (opcional, sobreescribe las globales)
database:
url: jdbc:postgresql://localhost:5432/megafactur_tenant1
username: ${DB_USER}
password: ${DB_PASSWORD}
maxPoolSize: 10
certificate:
path: ${CERT_PATH}
password: ${CERT_PASS}
company:
nif: B72877814
name: Empresa Demo S.L.
production: false
verifactuMode: true
autoMigrate: true
Instanciar ENGINE y mandar factura:
try (MegafacturEngine engine = MegafacturEngine.create(config)) {
engine.start(); // Crea automáticamente: BD → Flyway → JOOQ → Facades → Scheduler
// Crear una factura
InvoiceData factura = new InvoiceData();
factura.setInvoiceNumber("FACT-2024-001");
factura.setIssueDate(LocalDate.of(2024, 1, 15));
factura.setInvoiceTypeEnum(InvoiceType.F1);
factura.setTotalAmount(1210.00);
factura.setTaxAmount(210.00);
factura.setIssuerTaxId("B72877814");
factura.setIssuerName("Empresa Demo S.L.");
InvoiceResult resultado = engine.invoices().createInvoice(factura);
System.out.println("Hash: " + resultado.getHash());
System.out.println("Tamaño QR: " + resultado.getQrCode().length + " bytes");
// Forzar despacho a la AEAT
DispatchResult despacho = engine.dispatch().forceDispatch();
System.out.println(despacho.getMessage());
} // Cierre automático: detiene el scheduler y cierra el pool de conexiones
Realmente en 3 líneas de código se puede mandar la factura a la AEAT, ya que simplemente debes de mapear la factura a formato InvoiceData lo cual podría estar en una función de mapeo a parte.
Todos los métodos están documentados
Así como todos los campos relevantes, no hay datos mágicos todo es un ENUM bien definido
Implementación de bajo nivel que gestiona la comunicación con la AEAT, firma XadES, calculo Hash y especificacion Verifactu a bajo nivel.
• Este proyecto en su totalidad rechaza el uso indiscriminado del patrón DTO por lo que el modulo core es el unico source of truth, todos los modelos estan aqui. • De este modo se ahorran muchisimos mappers inecesarios, fricciones y posibles bugs tan comunes al mapear.
1. Crear factura 2. Validar datos 3. Generar hash 4. Firmar XML 5. Enviar a AEAT 6. Recibir respuesta 7. Gestionar estado
engine.invoices().rectifyInvoice(...)
Después de ejecutar una operación tendremos inmediatamente el QR en base 64 para incluir en la factura junto con la URL de validación:
{
"recordId": 42,
"hash": "A1B2C3D4E5F6...",
"validationUrl": "...",
"qrBase64": "...",
"state": "PENDING_DISPATCH"
}
Esto sera preciso añadirlo a la factura. Cuando mediante accion manual llamando al metodo de forzar envio, o el scheduler del engine envie la factura a la AEAT tendremos el resultado de la operación:
{
"valid": true,
"hashValid": true,
"linkValid": true,
"invoiceNumber": "invoiceNumber",
"expectedHash": "expectedHash",
"errorDetail": "errorDetail",
"actualHash": "actualHash"
}
De aquí se puede extraer el estado AEAT de la operación para incluirlo en el sistema: ACEPTADO, CORRECTO, ACEPTADO CON ERRORES
Error 1189 → falta destinatario (Factura tipo F1 sin destinatario) Solución → añadir destinatario y reenviar