Cómo automatizar
la facturación
con n8n + GPT-4o.
Guía práctica con código real. Al final de la lectura tienes un workflow que recibe facturas por email, extrae los datos con IA, valida contra tus órdenes de compra y registra en tu ERP. Sin teclear.
TL;DR
Un workflow n8n que escucha una casilla facturas@, envía cada PDF a GPT-4o para extracción estructurada, valida el CIF contra tu maestro de proveedores, cruza el importe con órdenes de compra abiertas y crea el registro en Holded/Odoo/Sage. Tiempo por factura: ~8 segundos. Sustituye 4–7 minutos de trabajo manual por factura. Este workflow está corriendo hoy en clientes reales procesando +8.000 facturas/mes.
Prerequisitos
- n8n 1.40+ self-hosted (Docker o Node). Versión Cloud también funciona pero con coste por ejecución.
- OpenAI API key con acceso a GPT-4o (modelo
gpt-4o-2024-08-06o superior). - Casilla de email dedicada con IMAP activo (ej.
[email protected]). - ERP con API. Holded, Odoo, Sage 200, Business Central — todos funcionan. Si tu ERP no tiene API oficial, miramos RPA.
- PostgreSQL para el log de procesamiento (o SQLite si eres muy espartano).
Paso 01Preparar el entorno n8n
Si aún no tienes n8n corriendo, la forma más rápida es Docker Compose. Este compose mínimo te deja n8n + Postgres corriendo en un VPS de 35€/mes:
# docker-compose.yml services: n8n: image: n8nio/n8n:1.40 restart: always ports: ["5678:5678"] environment: - DB_TYPE=postgresdb - DB_POSTGRESDB_HOST=postgres - N8N_ENCRYPTION_KEY=${N8N_KEY} - N8N_PROTOCOL=https - WEBHOOK_URL=https://n8n.tuempresa.com volumes: ["./data:/home/node/.n8n"] postgres: image: postgres:16 environment: - POSTGRES_PASSWORD=${PG_PASS} volumes: ["./pg:/var/lib/postgresql/data"]
Arranca con docker compose up -d, apunta un subdominio, pon un Caddy o Traefik delante para TLS, y entra a la UI para configurar credenciales.
Paso 02Configurar el trigger IMAP
Añade un nodo Email Trigger (IMAP) al canvas. Configura:
- Host: el IMAP de tu proveedor (ej.
imap.gmail.com,outlook.office365.com). - Mailbox:
INBOXo una carpeta específica si filtras por reglas. - Post-process: mover a carpeta
Procesadaspara no reprocesar. - Download attachments: activado, filtrado a
application/pdf.
facturas@ dedicado y da la dirección a tus proveedores. Así aíslas el flow de ruido y puedes borrar todo el histórico sin afectar otras bandejas.
Paso 03Extraer datos con GPT-4o Vision
Conecta el trigger a un nodo OpenAI · Message a Model. Modelo gpt-4o, modo JSON. El prompt clave:
// Prompt de extracción estructurada Eres un extractor de datos de facturas. Devuelve SIEMPRE JSON válido con esta forma: { "cif_proveedor": string, "nombre_proveedor": string, "numero_factura": string, "fecha_emision": string (ISO 8601), "base_imponible": number, "iva": number, "total": number, "moneda": string (ISO 4217), "lineas": [{ descripcion, cantidad, precio_unitario, total }], "confidence": number (0–1) } Si un campo no está claro, pon null y baja confidence. No inventes datos. No añadas comentarios. Solo JSON.
Pasa el PDF como input de imagen (GPT-4o lo convierte internamente). Para PDFs de más de 3 páginas, divide y procesa por página; luego fusiona.
Paso 04Validar contra proveedores y órdenes
Añade un nodo Code (JavaScript) después del OpenAI para validar. Lógica mínima:
const factura = $json; const errores = []; // 1. CIF debe existir en maestro de proveedores const proveedor = await $lookup('proveedores', { cif: factura.cif_proveedor }); if (!proveedor) errores.push('proveedor_desconocido'); // 2. Importe debe cuadrar con alguna orden abierta (±1%) const ordenes = await $lookup('ordenes_compra', { proveedor_cif: factura.cif_proveedor, estado: 'abierta' }); const match = ordenes.find(o => Math.abs(o.total - factura.total) / o.total < 0.01 ); if (!match) errores.push('sin_orden_coincidente'); // 3. Confidence mínimo if (factura.confidence < 0.85) errores.push('confidence_baja'); return { factura, orden: match, errores };
Usa un nodo IF después para bifurcar: si errores.length === 0, sigue al registro automático; si no, escala a humano (paso 6).
Paso 05Registrar en el ERP
Aquí cambia el nodo según tu ERP. Ejemplos reales:
- Holded: nodo HTTP Request a
POST /invoicing/v1/documents/purchasecon el JSON mapeado. - Odoo: nodo Odoo nativo, modelo
account.move, typein_invoice. - Sage 200: API REST vía HTTP Request + API key de usuario técnico.
Después del registro, sube el PDF original como adjunto al documento creado. Todos los ERPs modernos tienen endpoint /attachments para esto.
external_id que devuelve el ERP en tu Postgres local. Así puedes reconciliar y volver a buscar si algo falla.
Paso 06Escalar excepciones a humano
La rama de error del IF conecta a un nodo Slack (o Teams, Email, lo que uses). El mensaje debe incluir:
- Qué validación falló (
errores.join(', ')). - Resumen de la factura (proveedor, número, total).
- Link al PDF original guardado en S3 o tu file server.
- Botón "Aprobar manualmente" que dispara un webhook de vuelta a n8n para forzar el registro.
Errores comunes (y cómo evitarlos)
- PDFs escaneados con mala calidad → GPT-4o baja
confidence. Solución: pasar por un preprocess de imagen (nodoImagecon aumento de contraste) antes del OpenAI. - Facturas con moneda distinta al EUR → olvidas añadir conversión. Solución: nodo de tipo de cambio vía exchangerate.host antes de registrar.
- Proveedores que mandan un ZIP con varias facturas → el trigger solo coge el primer PDF. Solución: nodo
Extract from ZIPantes del OpenAI. - Timeout en facturas largas → aumenta el timeout del nodo OpenAI a 120s y divide PDFs de +5 páginas.
- Rate limit de OpenAI en picos de final de mes → activa retry con backoff exponencial (3 reintentos, base 2s).
Qué hacer después
Este workflow es la base. Una vez funcionando, las extensiones naturales son:
- Conciliación bancaria: un segundo flow que cruza pagos bancarios con estas facturas registradas. Guía →
- Previsión de tesorería: dashboard Grafana con vencimientos proyectados a 30/60/90. Guía →
- Detección de fraude: modelo que marca facturas con patrones anómalos (cambio súbito de IBAN del proveedor, importes fuera de rango histórico).
Si prefieres no construirlo tú, hablamos 30 minutos y lo dejamos corriendo en tu infra: 4 semanas de construcción + 4 de estabilización supervisada antes de pasar a producción 100 % autónoma. Fee cerrado.