Flujo 05: Extracción de Datos de PDFs con IA
El problema
Las facturas de proveedores llegan como PDFs por email. Alguien las abre una a una, busca el importe, la fecha, el NIF del proveedor, las líneas de detalle, y los teclea en el ERP o en una hoja de Excel. Con 20-30 facturas semanales, eso son 2-4 horas de trabajo manual con alta tasa de errores de transcripción. Claude 3.5 puede leer el texto de un PDF y extraer todos los campos en formato JSON en menos de 3 segundos por documento.
Herramientas necesarias
| Nodo n8n | Función |
|---|---|
| Gmail Trigger | Detecta emails con adjuntos PDF |
| Gmail | Descarga el archivo adjunto en base64 |
| Extract from File | Convierte el PDF binario a texto plano |
| HTTP Request | Llama a Claude API con el texto extraído |
| Google Sheets | Guarda los datos estructurados de cada factura |
Servicios externos:
- Cuenta Gmail con OAuth2 en n8n
- API Key de Anthropic (console.anthropic.com)
- Google Sheets con la hoja de facturas preparada
Configuración paso a paso
Nodo 1: Gmail Trigger
Configura el trigger para detectar emails con adjuntos PDF:
- Event: Message Received
- Filters > Query:
has:attachment filename:pdf(sintaxis de búsqueda de Gmail) - Simplify: OFF
- Download Attachments: ON
Importante: activa Download Attachments para que el nodo descargue el binario del adjunto directamente. Sin esto, solo recibes el metadata del email.
Campos disponibles:
{{ $json.attachments[0].name }} → nombre del archivo
{{ $json.attachments[0].data }} → contenido en base64
{{ $json.attachments[0].mimeType }} → tipo MIME
{{ $json.From }} → remitente del email
{{ $json.Subject }} → asunto del email
Nodo 2: IF — Filtrar solo PDFs
Añade un nodo IF para verificar que el adjunto es realmente un PDF y no una imagen u otro tipo de archivo:
- Condition:
- Value 1:
={{ $json.attachments[0].mimeType }} - Operation:
Contains - Value 2:
pdf
- Value 1:
Solo los emails con adjunto PDF real continúan el flujo.
Nodo 3: Extract from File
Añade el nodo Extract from File:
- Operation: Extract Text from PDF
- Binary Property:
={{ $json.attachments[0].data }}
Este nodo convierte el binario del PDF a texto plano. Para PDFs generados digitalmente (no escaneados) la extracción es prácticamente perfecta. Para PDFs escaneados necesitas un servicio de OCR externo antes de este paso.
El texto resultante estará en {{ $json.text }}.
Nodo 4: HTTP Request — Claude API (visión del documento)
Añade el nodo HTTP Request:
- Method: POST
- URL:
https://api.anthropic.com/v1/messages - Authentication: Header Auth
x-api-key: tu API Key de Anthropic
- Headers adicionales:
anthropic-version:2023-06-01content-type:application/json
- Body (JSON):
{
"model": "claude-3-5-haiku-20241022",
"max_tokens": 800,
"messages": [
{
"role": "user",
"content": "={{ $json.prompt_extraccion }}"
}
]
}
Crea el campo prompt_extraccion en un nodo Set previo:
Extrae los datos de esta factura y devuelve ÚNICAMENTE un JSON válido.
Si un campo no está en el documento, usa null.
Los importes deben ser números sin símbolo de moneda (ej: 1250.50).
Las fechas en formato DD/MM/YYYY.
JSON de salida requerido:
{
"numero_factura": "...",
"fecha_emision": "DD/MM/YYYY",
"fecha_vencimiento": "DD/MM/YYYY o null",
"proveedor_nombre": "...",
"proveedor_nif": "...",
"cliente_nombre": "...",
"cliente_nif": "...",
"base_imponible": número,
"iva_porcentaje": número,
"iva_importe": número,
"total_factura": número,
"concepto": "descripción breve del servicio o producto",
"lineas": [
{"descripcion": "...", "cantidad": número, "precio_unitario": número, "importe": número}
]
}
TEXTO DE LA FACTURA:
{{ $json.text }}
Nodo 5: Code — Parsear y validar JSON
Añade un nodo Code (JavaScript) para extraer y validar el JSON:
const respuesta = $input.first().json.content[0].text;
// Limpiar markdown si la IA lo añade
const limpio = respuesta.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim();
const datos = JSON.parse(limpio);
// Validación: campos obligatorios
const camposObligatorios = ['numero_factura', 'total_factura', 'proveedor_nombre'];
const camposFaltantes = camposObligatorios.filter(c => datos[c] === null || datos[c] === undefined);
if (camposFaltantes.length > 0) {
throw new Error(`Campos obligatorios faltantes: ${camposFaltantes.join(', ')}`);
}
return [{ json: {
...datos,
fecha_procesado: new Date().toISOString(),
archivo_fuente: $('Gmail Trigger').item.json.attachments[0].name,
remitente_email: $('Gmail Trigger').item.json.From,
estado: 'procesado_ok'
}}];
Nodo 6: Google Sheets — Guardar factura
Añade el nodo Google Sheets:
- Operation: Append Row
- Document ID: ID de tu hoja
- Sheet Name:
Facturas_Recibidas - Column Matching: By Column Name
- Columns: mapea cada campo del JSON a la columna correspondiente
Columnas recomendadas en la hoja:
Fecha_Procesado | Numero_Factura | Fecha_Emision | Fecha_Vencimiento | Proveedor | NIF_Proveedor | Base_Imponible | IVA_% | IVA_€ | Total | Concepto | Estado | Archivo
Ejemplo de prompt IA
Extrae los datos de esta factura y devuelve ÚNICAMENTE un JSON válido.
TEXTO DE LA FACTURA:
FACTURA Nº: F2025-0142
Fecha: 15/04/2025
Vencimiento: 30/04/2025
EMISOR:
Servicios Cloud SL
CIF: B-12345678
RECEPTOR:
Acme Corp SL
CIF: A-87654321
DETALLE:
- Licencias software anual (5 usuarios) × 1 ... 2.500,00€
- Soporte técnico mensual × 1 ................... 450,00€
Base imponible: 2.950,00€
IVA 21%: 619,50€
TOTAL: 3.569,50€
Respuesta de Claude:
{
"numero_factura": "F2025-0142",
"fecha_emision": "15/04/2025",
"fecha_vencimiento": "30/04/2025",
"proveedor_nombre": "Servicios Cloud SL",
"proveedor_nif": "B-12345678",
"cliente_nombre": "Acme Corp SL",
"cliente_nif": "A-87654321",
"base_imponible": 2950.00,
"iva_porcentaje": 21,
"iva_importe": 619.50,
"total_factura": 3569.50,
"concepto": "Licencias software y soporte técnico",
"lineas": [
{"descripcion": "Licencias software anual (5 usuarios)", "cantidad": 1, "precio_unitario": 2500.00, "importe": 2500.00},
{"descripcion": "Soporte técnico mensual", "cantidad": 1, "precio_unitario": 450.00, "importe": 450.00}
]
}
Ahorro estimado
| Tarea | Antes | Con automatización |
|---|---|---|
| Abrir y revisar 25 PDFs/semana | 30 min/semana | 0 min |
| Teclear datos en sistema | 2 h/semana | 0 min |
| Revisar errores de transcripción | 30 min/semana | 5 min (revisión spot) |
| Total semanal | 3 h/semana | ~5 min/semana |
Ahorro neto: ~2,9 horas/semana. Tasa de error en transcripción manual: 3-5%. Con IA sobre PDFs digitales: <1%. Coste de Claude por factura procesada: ~€0,001.