Facturas de transporte sin teclear
Cómo montar en n8n un circuito que lee facturas de fletes con Gemini, las valida y las registra en Business Central sin que nadie teclee un importe.

El problema: facturas que nadie revisa del todo
En logística, validar a mano las facturas de transporte es lento y deja pasar errores. Una factura de flete no es una factura cualquiera: el importe sale de combinar transportista, ruta, peso, tipo de servicio, tramo de tarifa, recargo de combustible y cargos accesorios. Cuando alguien la revisa con prisa, los errores casi siempre favorecen al transportista.

| Dónde se escapa el dinero | Qué hace falta para reclamar |
|---|---|
| Peso o zona mal clasificados | Ficha técnica, ticket de báscula, foto en muelle |
| Cargos accesorios que no se pidieron | Albarán firmado, registro GPS, tarifa pactada |
Y viene la factura electrónica obligatoria. La Ley 18/2022 («Crea y Crece») obliga a la factura electrónica estructurada entre empresas. Durante la transición convivirán XML de los grandes operadores con PDFs de pymes, y los OCR basados en plantillas no aguantan esa variedad.
Las piezas
- ERP: Microsoft Dynamics 365 Business Central, por OData V4 (endpoints
purchaseInvoicesypurchaseInvoiceLines) con OAuth 2.0. - Lectura de documentos: Gemini en Vertex AI. Lee el PDF completo y devuelve JSON con un esquema estricto y temperatura 0.
- Orquestación: n8n en servidor propio. Permite código Node.js (zod, crypto), mantiene los datos en casa y controla el ritmo de llamadas para no saturar el ERP.
- Cola de errores: PostgreSQL. Lo que falla se guarda para reintentarlo; ninguna factura se pierde por un corte de red.
El flujo, paso a paso

Entrada segura: webhooks firmados
El webhook de n8n recibe el cuerpo en bruto («Raw Body») para poder comprobar la firma HMAC-SHA256 del emisor en un nodo de código. Sin firma válida, la petición no entra:
const crypto = require('crypto');
const signature = headers['x-signature'];
const secret = $env.WEBHOOK_HMAC_SECRET;
const payload = `${headers['x-timestamp']}.${rawBody}`;
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature || ''), Buffer.from(expected))) {
throw new Error('Firma HMAC no válida');
}Extracción sin sorpresas
A Gemini se le exige una estructura fija mediante generationConfig. Si la respuesta no cumple el esquema, zod la rechaza y la factura va a revisión humana en lugar de colarse en el ERP:
"generationConfig": {
"temperature": 0.0,
"responseMimeType": "application/json",
"responseSchema": {
"type": "OBJECT",
"properties": {
"invoice_id": { "type": "STRING" },
"vendor_vat": { "type": "STRING" },
"total_amount_incl_vat": { "type": "NUMBER" }
},
"required": ["invoice_id", "vendor_vat", "total_amount_incl_vat"]
}
}Escribir en el ERP sin saturarlo
Las líneas de detalle se envían una a una con el nodo Loop Over Items (lotes de 1) y un nodo Wait de 1.000 ms entre llamadas. Más lento que en paralelo, pero Business Central no devuelve errores de concurrencia y cada línea queda trazada.

¿Quieres el flujo?
Te pasamos el JSON exportado de n8n con la validación, el webhook firmado y el prompt de extracción, listo para importar en tu instancia. Pídelo por WhatsApp y cuéntanos qué ERP usas.
¿Prefieres que lo montemos nosotros? Mira cómo trabajamos la automatización de procesos.