1. Visión General del Servicio
UnitaGo es la plataforma integral de inteligencia artificial y middleware conectada en tiempo real a vuestro ERP propio (MasterGest / MySQL). Centraliza en una sola infraestructura la automatización contable de compras, el comercio conversacional en WhatsApp, la gestión de deuda con cobros directos en Redsys y la orquestación cognitiva con RAG y n8n.
Ingestión de PDFs o fotos (JPG/PNG) de compras de proveedores con Claude Sonnet 5.5 / Haiku 5.5. Extracción estricta con Tool Calling: emisor, receptor, bases imponibles, desglose múltiple de IVA, recargo, retenciones IRPF y líneas de detalle para contabilización automática.
Atención 24/7 vía WhatsApp oficial. Identifica clientes por teléfono en MySQL, calcula precios con proc_dame_precio (o tarifa general CodTarifa=0 si no está registrado), busca por nombre o CodTrabajo, gestiona "lo de siempre" e inserta pedidos en Pedido_Cab y Pedido_Det.
Consulta instantánea de facturas, albaranes y saldo pendiente (Pdte). Genera referencias de pago de deuda con prefijo AG... y registra la petición en PagosPeticiones vinculada a Redsys, lista para su conciliación asíncrona por el worker (redsys_notificaciones).
Copiloto web con búsqueda semántica en la documentación corporativa (doc.neod.es). Integración nativa con agentes autónomos en n8n mediante Webhooks y 5 herramientas API dedicadas, con conmutación por fallo automática (failover) a prueba de cortes.
Aislamiento total por empresa o cliente ERP: cada emisor conecta con su propia base de datos MySQL (host, puerto, credenciales), claves de API independientes (ndg_live_...), márgenes comerciales configurables y límites mensuales de gasto (€) con corte de seguridad automático.
2. Autenticación (Tokens por Empresa)
Cada empresa cliente o tenant tiene asignado un token API privado con prefijo ndg_live_.... Este token identifica a la empresa, aplica su tarifa/margen configurado y controla su límite presupuestario mensual.
Envío de la cabecera en cada petición:
Se debe incluir la cabecera HTTP X-API-Key en la llamada (también se acepta Authorization: Bearer <token>):
3. URL Base y Servidores
| Entorno | URL Base | Descripción |
|---|---|---|
| Local (Pruebas / Desarrollo) | http://localhost:3000 |
Servidor local durante la fase de integración. |
| Producción (Hostinger) | https://ia.tudominio.com |
Subdominio en Node.js desplegado en el Hosting. |
4. Ingestión de Facturas (Extracción IA)
/api/v1/invoices/process
Endpoint principal consumido por el ERP. Recibe el archivo de la factura, invoca a Claude para la extracción con Tool Calling y devuelve los datos estructurados en formato JSON.
Cabeceras Requeridas (Headers)
| Header | Tipo | Valor / Ejemplo |
|---|---|---|
X-API-Key |
Obligatorio | ndg_live_demo_1234567890abcdef1234567890abcdef |
Content-Type |
Obligatorio | multipart/form-data |
Parámetros de la Petición (Multipart Form Data)
| Campo | Tipo | Estado | Descripción |
|---|---|---|---|
file (o invoice) |
Archivo Binario | Obligatorio | Documento escaneado o foto. Formatos admitidos: PDF, JPG, PNG, WEBP (hasta 25 MB). |
| invoiceIdErp | String | Opcional | Código o ID del registro en vuestro ERP para vincular la auditoría y consumos (ej: FAC-2026-0042). |
| model | String | Opcional | Permite forzar un modelo específico: • claude-sonnet-5-5 (Recomendado - Máxima precisión para facturas complejas)• claude-haiku-5-5 (Ultrarrápido y coste reducido)Si se omite, se usa el modelo preferido configurado para la empresa en el panel admin. |
| customInstructions | String | Opcional | Instrucción contextual adicional para la IA ante peculiaridades del proveedor. |
Respuesta Exitosa (HTTP 200 OK)
Estructura de respuesta devuelta por el middleware, con clasificación de tipo de documento (Factura o Albarán) y trazabilidad completa de lotes y fechas de caducidad por línea:
{
"success": true,
"data": {
"tipo_documento": "Factura", // "Factura" | "Albaran"
"emisor": {
"razon_social": "Suministros Industriales S.L.",
"cif_nif": "B87654321",
"direccion": "Polígono Industrial Nave 12",
"codigo_postal": "28001",
"poblacion": "Madrid",
"pais": "ES",
"telefono": "912345678",
"email": "facturacion@suministros.es"
},
"receptor": {
"razon_social": "Mi Empresa Cliente S.L.",
"cif_nif": "B12345678",
"direccion": "Calle Mayor 10, Málaga",
"codigo_postal": "29001",
"poblacion": "Málaga",
"pais": "ES"
},
"factura": {
"numero_factura": "F-2026/0891", // Número de factura o número de albarán
"serie": "F",
"fecha_emision": "2026-10-15",
"fecha_vencimiento": "2026-11-15",
"forma_pago": "Transferencia bancaria a 30 días",
"iban": "ES9121000418450200051332"
},
"desglose_impuestos": [
{
"tipo_iva": 21,
"base_imponible": 1000.00,
"cuota_iva": 210.00,
"recargo_equivalencia": 0
}
],
"retencion_irpf": {
"aplica": false,
"porcentaje": 0,
"importe_retenido": 0
},
"lineas_detalle": [
{
"descripcion": "Aceite de Oliva Virgen Extra 5L",
"referencia": "AOVE-5L",
"cantidad": 10,
"precio_unitario": 42.50,
"descuento_porcentaje": 0,
"tipo_iva": 10,
"importe_linea": 425.00,
"lote_partida": ["L-24091A", "L-24091B"], // Uno o múltiples lotes por línea
"fecha_caducidad": "2027-06-30", // Formato ISO AAAA-MM-DD o null
"lotes": [
{
"lote": "L-24091A",
"fecha_caducidad": "2027-06-30",
"cantidad": 6
},
{
"lote": "L-24091B",
"fecha_caducidad": "2027-06-30",
"cantidad": 4
}
]
},
{
"descripcion": "Harina de Trigo Especial Fuerza 25kg",
"referencia": "HAR-ESP-25",
"cantidad": 5,
"precio_unitario": 115.00,
"descuento_porcentaje": 0,
"tipo_iva": 4,
"importe_linea": 575.00,
"lote_partida": ["PART-8894"],
"fecha_caducidad": "2026-12-15",
"lotes": [
{
"lote": "PART-8894",
"fecha_caducidad": "2026-12-15",
"cantidad": 5
}
]
}
],
"totales": {
"subtotal_base_imponible": 1000.00,
"total_iva": 65.50,
"total_retencion": 0.00,
"total_factura": 1065.50,
"moneda": "EUR"
},
"auditoria_ia": {
"calidad_documento": "alta",
"tipo_documento_sugerido": "Factura",
"notas_o_advertencias": null
}
},
"meta": {
"tipo_documento": "Factura", // Acceso directo al tipo sin parsear data
"client": {
"id": 1,
"name": "Empresa Demo ERP",
"cif": "B12345678"
},
"processing": {
"modelUsed": "claude-sonnet-5-5",
"durationMs": 2840,
"tokens": {
"input": 1420,
"output": 680,
"total": 2100
},
"billedCostEur": 0.0163
}
}
}
📦 Especificación de Campos de Clasificación y Trazabilidad (Facturas y Albaranes)
| Campo | Tipo | Presencia | Descripción y Reglas de Negocio |
|---|---|---|---|
| data.tipo_documento | String | Garantizado |
Indica el tipo de documento clasificado por la IA: "Factura" o "Albaran" (remisiones, notas de entrega o conduces).
|
| data.factura.numero_factura | String | Garantizado | Identificador alfanumérico del documento (número de factura comercial o número de albarán del proveedor). |
| data.lineas_detalle[].lote_partida | Array<String> | Garantizado |
Array con los códigos de lote o partidas de trazabilidad detectados para el artículo. Si el artículo comprende más de un lote se devuelven todos (ej: ["LOT-01", "LOT-02"]); si no aplica, devuelve un array vacío [].
|
| data.lineas_detalle[].fecha_caducidad | String | null | Opcional |
Fecha de caducidad o consumo preferente en formato estándar ISO AAAA-MM-DD (ej: "2027-06-30"), o null si el producto no tiene fecha de caducidad.
|
| data.lineas_detalle[].lotes | Array<Object> | Opcional |
Desglose individual por lote con los campos lote, fecha_caducidad y cantidad asignada a ese lote cuando el documento detalla el desglose por bultos o partidas.
|
| data.auditoria_ia.tipo_documento_sugerido | String | Garantizado |
Tipo sugerido por la capa cognitiva de auditoría: "Factura" o "Albaran".
|
| meta.tipo_documento | String | Garantizado |
Acceso directo en la cabecera meta para que el ERP determine si enrutar la carga a su tabla de facturas de compra o a su tabla de albaranes de entrada sin necesidad de parsear todo el árbol de datos.
|
5. Consulta de Presupuesto y Consumo del Cliente
/api/v1/invoices/my-usage
Permite al ERP comprobar en cualquier momento el gasto acumulado en el mes en curso y saber si la empresa puede continuar procesando facturas o si requiere ampliar presupuesto.
Headers requeridos:
X-API-Key: ndg_live_...
{
"success": true,
"client": {
"id": 1,
"name": "Empresa Demo ERP",
"preferredModel": "claude-sonnet-5-5"
},
"usage": {
"allowed": true,
"currentSpend": 12.45,
"budget": 50.00
}
}
6. Listado de Empresas Activas
/api/v1/companies/active
Devuelve la lista de empresas dadas de alta y activas en el middleware. Utilizado para alimentar selectores en interfaces de escaneo o sincronizadores del ERP.
{
"success": true,
"data": [
{
"id": 1,
"name": "Empresa Demo ERP",
"cif": "B12345678",
"apiKey": "ndg_live_demo_1234567890abcdef1234567890abcdef",
"preferredModel": "claude-sonnet-5-5"
}
]
}
7. Exportación a Excel (.xlsx), CSV y JSON
/api/v1/invoices/export
Convierte una o varias facturas procesadas en un libro de Excel (.xlsx) estructurado en 2 pestañas (Facturas y Líneas de Detalle) o en formato CSV separado por punto y coma (;) con BOM UTF-8 para apertura inmediata en Excel en español.
Cuerpo de la petición (JSON Content-Type: application/json):
{
"format": "excel", // "excel" | "csv" | "json"
"invoices": [
{
"fileName": "factura_proveedor_01.pdf",
"data": { ... } // Estructura de data devuelta por /invoices/process
}
]
}
8. Estado del Sistema y Base de Datos
/health
Endpoint público de diagnóstico para monitorización de uptime y comprobación de la conexión con MySQL.
{
"status": "ok",
"service": "UnitaGo AI Invoice Middleware",
"dbConnected": true,
"timestamp": "2026-10-23T15:00:00.000Z"
}
9. Detalle del Esquema JSON Contable
A continuación se describen los campos exactos generados para cada sección de la factura:
9.1 Emisor (Proveedor) & Receptor (Cliente)
| Campo | Tipo | Descripción |
|---|---|---|
razon_social | String | Nombre comercial o razón social completa. |
cif_nif | String | NIF/CIF español o VAT number europeo (sin guiones extraños). |
direccion | String | Dirección fiscal o sede del proveedor/cliente. |
codigo_postal | String | Código postal si está presente en el membrete. |
poblacion | String | Ciudad / municipio. |
pais | String | Código ISO 2 letras (ej: ES, FR, DE). |
iban | String | Código IBAN bancario extraído del pie de factura para la orden de pago. |
9.2 Desglose de Impuestos (IVA, Recargo e IRPF)
El array desglose_impuestos separa cada tipo de IVA presente en la factura (ej: 21%, 10%, 4%, 0%):
| Campo | Tipo | Descripción |
|---|---|---|
tipo_iva | Number | Porcentaje aplicado (21, 10, 4, 0). |
base_imponible | Number | Base imponible correspondiente a ese tipo de gravamen. |
cuota_iva | Number | Cuota de IVA calculada (base * tipo / 100). |
recargo_equivalencia | Number | Recargo de equivalencia si aplica (comercio minorista). |
El objeto retencion_irpf gestiona las retenciones de profesionales autónomos (ej: 15% o 7%):
| Campo | Tipo | Descripción |
|---|---|---|
aplica | Boolean | true si la factura tiene retención de IRPF, false si no. |
porcentaje | Number | Porcentaje de retención (ej: 15.00). |
importe_retenido | Number | Importe total retenido a restar del pago. |
9.3 Líneas de Detalle (Artículos / Servicios)
| Campo | Tipo | Descripción |
|---|---|---|
descripcion | String | Concepto o descripción del artículo o servicio. |
referencia | String / null | Código de referencia, SKU o código de proveedor. |
cantidad | Number | Unidades facturadas (por defecto 1). |
precio_unitario | Number | Precio por unidad sin impuestos. |
descuento_porcentaje | Number | Descuento comercial por línea si aplica (0 a 100). |
tipo_iva | Number | Tipo de IVA de esta línea específica. |
importe_linea | Number | Importe neto total de la línea. |
10. Ejemplos de Implementación en el ERP
Código listo para incorporar directamente en vuestro proyecto Delphi. Incluye la unidad completa con el cliente TUnitaGoClient usando componentes modernos nativos (System.Net.HttpClient y System.JSON), la integración visual de Neo Copilot en un formulario Delphi (TForm con TEdgeBrowser), y la alternativa con Indy (TIdHTTP) para versiones anteriores del compilador.
Haz clic en el lenguaje empleado en vuestro ERP para ver el código de ejemplo listo para copiar y pegar:
unit uUnitaGoClient;
{==============================================================================
INTEGRACIÓN OFICIAL UNITAGO AI MIDDLEWARE PARA ERP EN DELPHI
Compatible con: Delphi XE8, 10 Seattle, 10.1 Berlin, 10.2 Tokyo,
10.3 Rio, 10.4 Sydney, 11 Alexandria, 12 Athens.
Utiliza System.Net.HttpClient (WinHTTP nativo, sin DLLs externas de OpenSSL)
==============================================================================}
interface
uses
System.SysUtils, System.Classes, System.Net.HttpClient, System.Net.Mime,
System.Net.URLClient, System.JSON;
type
EUnitaGoException = class(Exception);
///
/// Cliente para el envío y extracción con IA de facturas de compras
///
TUnitaGoClient = class
private
FBaseUrl: string;
FApiKey: string;
FTimeoutMs: Integer;
public
constructor Create(const ABaseUrl, AApiKey: string; ATimeoutMs: Integer = 60000);
///
/// Envía la factura escaneada y devuelve el TJSONObject 'data' estructurado.
/// Es responsabilidad del llamador liberar el objeto resultante (Result.Free).
///
function ProcesarFactura(const ARutaArchivo: string; const AInvoiceIdErp: string = ''; const AModelo: string = ''): TJSONObject;
///
/// Consulta el saldo y presupuesto disponible del mes en curso para el ERP.
///
function ConsultarConsumoMes: TJSONObject;
end;
implementation
constructor TUnitaGoClient.Create(const ABaseUrl, AApiKey: string; ATimeoutMs: Integer);
begin
inherited Create;
FBaseUrl := ABaseUrl.TrimRight(['/']);
FApiKey := AApiKey;
FTimeoutMs := ATimeoutMs;
end;
function TUnitaGoClient.ProcesarFactura(const ARutaArchivo, AInvoiceIdErp, AModelo: string): TJSONObject;
var
LHttpClient: THTTPClient;
LMultipart: TMultipartFormData;
LResponse: IHTTPResponse;
LJsonRoot: TJSONObject;
LData: TJSONObject;
LUrl: string;
begin
Result := nil;
if not FileExists(ARutaArchivo) then
raise EUnitaGoException.CreateFmt('No existe el archivo de factura: %s', [ARutaArchivo]);
LHttpClient := THTTPClient.Create;
LMultipart := TMultipartFormData.Create;
try
LHttpClient.ConnectionTimeout := 20000;
LHttpClient.ResponseTimeout := FTimeoutMs;
// 1. Cabecera obligatoria de autenticación por empresa
LHttpClient.CustomHeaders['X-API-Key'] := FApiKey;
// 2. Adjuntar el archivo escaneado (campo multipart 'file')
LMultipart.AddFile('file', ARutaArchivo);
// 3. Parámetros opcionales para trazabilidad
if AInvoiceIdErp <> '' then
LMultipart.AddField('invoiceIdErp', AInvoiceIdErp);
if AModelo <> '' then
LMultipart.AddField('model', AModelo);
// 4. Invocación HTTP POST
LUrl := FBaseUrl + '/api/v1/invoices/process';
LResponse := LHttpClient.Post(LUrl, LMultipart);
// 5. Validar respuesta y parsear JSON
if LResponse.StatusCode <> 200 then
raise EUnitaGoException.CreateFmt('Error HTTP %d desde UnitaGo: %s',
[LResponse.StatusCode, LResponse.ContentAsString(TEncoding.UTF8)]);
LJsonRoot := TJSONObject.ParseJSONValue(LResponse.ContentAsString(TEncoding.UTF8)) as TJSONObject;
if not Assigned(LJsonRoot) then
raise EUnitaGoException.Create('La respuesta del servidor no es un JSON válido');
try
if not LJsonRoot.GetValue('success', False) then
raise EUnitaGoException.CreateFmt('Fallo de extracción IA: %s',
[LJsonRoot.GetValue('message', 'Error desconocido')]);
LData := LJsonRoot.GetValue('data');
if not Assigned(LData) then
raise EUnitaGoException.Create('No se encontró el nodo "data" en la respuesta');
Result := LData.Clone as TJSONObject;
finally
LJsonRoot.Free;
end;
finally
LMultipart.Free;
LHttpClient.Free;
end;
end;
function TUnitaGoClient.ConsultarConsumoMes: TJSONObject;
var
LHttpClient: THTTPClient;
LResponse: IHTTPResponse;
begin
Result := nil;
LHttpClient := THTTPClient.Create;
try
LHttpClient.CustomHeaders['X-API-Key'] := FApiKey;
LResponse := LHttpClient.Get(FBaseUrl + '/api/v1/invoices/my-usage');
if LResponse.StatusCode = 200 then
Result := TJSONObject.ParseJSONValue(LResponse.ContentAsString(TEncoding.UTF8)) as TJSONObject;
finally
LHttpClient.Free;
end;
end;
// =========================================================================
// EJEMPLO DE USO DESDE UN FORMULARIO O DATASET DEL ERP:
// =========================================================================
{
procedure TfrmFacturasCompra.btnEscanearFacturaClick(Sender: TObject);
var
LClient: TUnitaGoClient;
LFactura: TJSONObject;
LEmisor, LDatosFactura, LTotales, LLinea: TJSONObject;
LLineas: TJSONArray;
I: Integer;
begin
LClient := TUnitaGoClient.Create(
'http://localhost:3000', // En producción: https://ia.tudominio.com
'ndg_live_demo_1234567890abcdef1234567890abcdef'
);
try
Screen.Cursor := crHourGlass;
try
LFactura := LClient.ProcesarFactura('C:\Scans\Factura_001.pdf', 'DOC-ERP-2026');
try
LEmisor := LFactura.GetValue('emisor');
LDatosFactura := LFactura.GetValue('factura');
LTotales := LFactura.GetValue('totales');
// Asignación directa a tablas contables del ERP (ej: FireDAC / Zeos / ADO):
qryFacturas.Append;
qryFacturas.FieldByName('PROV_NOMBRE').AsString := LEmisor.GetValue('razon_social', '');
qryFacturas.FieldByName('PROV_CIF').AsString := LEmisor.GetValue('cif_nif', '');
qryFacturas.FieldByName('NUM_FACTURA').AsString := LDatosFactura.GetValue('numero_factura', '');
qryFacturas.FieldByName('FECHA').AsString := LDatosFactura.GetValue('fecha_emision', '');
qryFacturas.FieldByName('IBAN').AsString := LDatosFactura.GetValue('iban', '');
qryFacturas.FieldByName('BASE_IMPONIBLE').AsFloat := LTotales.GetValue('subtotal_base_imponible', 0);
qryFacturas.FieldByName('TOTAL_IVA').AsFloat := LTotales.GetValue('total_iva', 0);
qryFacturas.FieldByName('TOTAL_FACT').AsFloat := LTotales.GetValue('total_factura', 0);
qryFacturas.Post;
// Líneas de artículos:
LLineas := LFactura.GetValue('lineas_detalle');
if Assigned(LLineas) then
begin
for I := 0 to LLineas.Count - 1 do
begin
LLinea := LLineas.Items[I] as TJSONObject;
qryLineas.Append;
qryLineas.FieldByName('DESCRIPCION').AsString := LLinea.GetValue('descripcion', '');
qryLineas.FieldByName('REFERENCIA').AsString := LLinea.GetValue('referencia', '');
qryLineas.FieldByName('CANTIDAD').AsFloat := LLinea.GetValue('cantidad', 1);
qryLineas.FieldByName('PRECIO').AsFloat := LLinea.GetValue('precio_unitario', 0);
qryLineas.FieldByName('TOTAL').AsFloat := LLinea.GetValue('importe_linea', 0);
qryLineas.Post;
end;
end;
ShowMessage('Factura contabilizada automáticamente con éxito.');
finally
LFactura.Free;
end;
finally
Screen.Cursor := crDefault;
end;
finally
LClient.Free;
end;
end;
}
end.
11. Códigos de Estado y Manejo de Errores
Todas las respuestas que no sean exitosas devuelven un código HTTP correspondiente con cuerpo JSON estándar ({ "success": false, "error": "CODIGO", "message": "Detalle explicativo" }):
| Código HTTP | Código Error (JSON) | Causa y Acción Recomendada |
|---|---|---|
| 200 OK | - | Factura procesada con éxito. Los datos estructurados se encuentran en la propiedad data. |
| 400 Bad Request | FILE_REQUIRED |
No se adjuntó archivo o el formato no es compatible (debe ser PDF, JPG, PNG o WEBP de hasta 25 MB). |
| 401 Unauthorized | INVALID_API_KEY |
Falta la cabecera X-API-Key o el token proporcionado no existe en el sistema. |
| 403 Forbidden | CLIENT_DEACTIVATED |
La empresa cliente asociada al token ha sido pausada o desactivada por el administrador. |
| 429 Too Many Requests | BUDGET_EXCEEDED |
La empresa ha alcanzado el límite presupuestario mensual (€) configurado. Debe ser ampliado en el panel admin. |
| 502 Bad Gateway | AI_EXTRACTION_FAILED |
El documento está completamente ilegible, borroso o el proveedor de IA tuvo un error temporal. |
12. Orquestador de Agentes IA & n8n en Hostinger VPS
Esta sección es una guía práctica integral pensada para ti y tus compañeros de equipo. Explica en detalle cómo funciona la orquestación cognitiva entre UnitaGo y n8n, cómo desplegarlo en pocos minutos en vuestro servidor VPS de Hostinger y cómo poner a funcionar el agente de inteligencia artificial con la plantilla oficial pre-construida sin tener que montar flujos desde cero.
12.1. ¿Cómo funciona la arquitectura UnitaGo + n8n?
En esta arquitectura híbrida, n8n actúa como el motor cognitivo de agentes inteligentes (LangChain AI Agent), mientras que UnitaGo actúa como el middleware pasarela encargado del aislamiento multi-tenant, la integración con WhatsApp Cloud API, la seguridad y el acceso transaccional a las bases de datos de clientes y al ERP MasterGest.
🔄 Ciclo de Vida de una Conversación (WhatsApp / Web Copilot)
- Recepción del Mensaje: Un cliente final escribe por WhatsApp o mediante el asistente web Neo Copilot (ej. "¿A qué precio tenéis la caja de cerveza Alhambra y qué tengo pendiente de pago?").
- Identificación de Cliente: UnitaGo detecta el número de teléfono emisor, localiza su ficha de cliente en la base de datos MySQL de la empresa emisora y verifica si el orquestador n8n está activado en el panel.
- Invocación al Webhook de n8n: Si n8n está activo, UnitaGo delega la conversación enviando un webhook
POST https://n8n.tudominio.com/webhook/neod-copilottransmitiendo el mensaje del usuario,sessionId,clientId, el nombre del cliente y su teléfono. - Razonamiento Autónomo del AI Agent: El nodo AI Agent de n8n evalúa la consulta usando su memoria conversacional (
Window Buffer Memory) y su modelo LLM (OpenAI GPT-4o-mini, Anthropic Claude Sonnet 5.5 o Google Gemini). El agente razona y decide autónomamente qué herramientas invocar para recopilar la información necesaria. - Llamada a las Herramientas API de UnitaGo: n8n ejecuta los endpoints internos de UnitaGo: búsqueda semántica en la documentación corporativa (RAG), consulta del catálogo de artículos y stock, cálculo oficial de tarifas con
CALL proc_dame_precioo inserción de pedidos enPedido_CabyPedido_Det. - Respuesta Estructurada: n8n genera la respuesta final y la devuelve a UnitaGo en formato JSON estructurado:
{ "reply": "...", "provider": "n8n", "sources": [...] }. - Entrega al Cliente: UnitaGo formatea y entrega el mensaje final al cliente en WhatsApp o en la interfaz web de Neo Copilot.
12.2. Plantilla Oficial Pre-construida (Importación en 1 Clic)
No tenéis que construir ni conectar nodos desde cero. Hemos empaquetado el workflow oficial completo, con el agente de IA LangChain, el modelo conversacional, la memoria y las 5 herramientas HTTP totalmente cableadas y parametrizadas para UnitaGo.
neod_copilot_workflow_n8n.json
Pasos para importarlo en vuestro n8n:
- Accede a vuestro panel de n8n (ej.
https://n8n.tudominio.com). - En el menú lateral izquierdo, pulsa en Workflows y luego en + Add Workflow.
- En la esquina superior derecha del lienzo, haz clic en el botón de tres puntos (
...) y selecciona Import from File. - Selecciona el archivo descargado
neod_copilot_workflow_n8n.json. ¡Todo el flujo aparecerá instantáneamente conectado! - Haz doble clic en el nodo OpenAI Chat Model (o sustitúyelo por el nodo de Anthropic Claude o Gemini) para asociar vuestra API Key.
- Activa el interruptor Active en la esquina superior derecha para habilitar el webhook en modo producción.
12.3. Guía de Instalación Paso a Paso en Hostinger VPS (KVM 8)
El servidor VPS Hostinger KVM 8 (con Ubuntu 22.04 / 24.04 LTS, 8 vCPUs y 32 GB RAM) cuenta con potencia de sobra para alojar n8n en un contenedor Docker con volumen persistente, administrado mediante Nginx como proxy inverso y certificado SSL gratuito de Let's Encrypt.
Paso 1: Configurar el Registro DNS del Subdominio
En vuestro panel de dominio (Hostinger hPanel, Cloudflare o vuestro proveedor de DNS), cread un registro tipo A que apunte a la IP pública del servidor VPS:
| Tipo | Nombre / Host | Valor / Destino | TTL |
|---|---|---|---|
A |
n8n (o n8n.tudominio.com) |
IP_DE_VUESTRO_VPS_HOSTINGER |
300 seg (o Automático) |
Paso 2: Instalar Docker y Docker Compose en el VPS
# 1. Conectarse por SSH a la máquina de Hostinger ssh root@IP_DE_VUESTRO_VPS # 2. Actualizar paquetes del sistema apt update && apt upgrade -y # 3. Instalar Docker oficial mediante el script automatizado curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh # 4. Instalar el plugin de Docker Compose apt install -y docker-compose-plugin # 5. Comprobar que Docker está activo docker --version && docker compose version
Paso 3: Crear el Directorio y docker-compose.yml de n8n
Creamos la carpeta /opt/n8n con almacenamiento persistente en disco y reinicio automático ante reinicios del VPS:
# 1. Crear directorio para n8n
mkdir -p /opt/n8n && cd /opt/n8n
# 2. Crear el archivo docker-compose.yml (reemplaza n8n.tudominio.com por tu subdominio real)
cat <<'EOF' > docker-compose.yml
version: '3.8'
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
container_name: n8n_copilot
restart: always
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=n8n.tudominio.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://n8n.tudominio.com/
- GENERIC_TIMEZONE=Europe/Madrid
- N8N_DEFAULT_BINARY_DATA_MODE=filesystem
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=168
volumes:
- /opt/n8n/n8n_data:/home/node/.n8n
volumes:
n8n_data:
EOF
# 3. Levantar el contenedor de n8n en segundo plano
docker compose up -d
# 4. Verificar que el contenedor está levantado y corriendo
docker compose ps
Paso 4: Configurar Nginx Reverse Proxy y Certificado SSL (Let's Encrypt)
Configuramos Nginx para redirigir las peticiones externas HTTPS al puerto local 5678 con soporte de WebSockets:
# 1. Crear la configuración del sitio en Nginx (ajusta el nombre del subdominio)
cat <<'EOF' > /etc/nginx/sites-available/n8n
server {
listen 80;
server_name n8n.tudominio.com;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
}
}
EOF
# 2. Habilitar el sitio y recargar Nginx
ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# 3. Generar e instalar el certificado SSL gratuito con Certbot
apt install -y certbot python3-certbot-nginx
certbot --nginx -d n8n.tudominio.com --non-interactive --agree-tos -m admin@tudominio.com
12.4. Las 5 Herramientas API Expuestas por UnitaGo para el AI Agent
Para que el agente de n8n interactúe de forma segura con el ERP y la base de conocimiento corporativa, UnitaGo expone 5 endpoints protegidos con la cabecera X-Webhook-Secret (o Authorization: Bearer <token>):
| Herramienta (Tool Name) | Endpoint HTTP | Propósito y Parámetros |
|---|---|---|
tool_buscar_documentacion_rag |
POST /api/v1/n8n/knowledge-search |
Búsqueda semántica en RAG sobre la documentación corporativa (doc.neod.es).Body: { "query": "política devoluciones", "limit": 4 }
|
tool_buscar_catalogo_articulos |
POST /api/v1/n8n/query-catalog |
Consulta en tiempo real en la BD MySQL de artículos, stock y descripción, permitiendo búsqueda por nombre o por código CodTrabajo.Body: { "term": "Alhambra", "clientId": 1 }
|
tool_pedir_lo_de_siempre |
POST /api/v1/n8n/query-habituals |
Recupera los productos más comprados por el cliente desde la tabla Clientes_has_Articulos.Body: { "phone": "655112233", "clientId": 1 }
|
tool_calcular_precio_oficial |
POST /api/v1/n8n/calculate-price |
Ejecuta el procedimiento almacenado oficial CALL proc_dame_precio(...). Aplica tarifa general CodTarifa=0 si no está registrado.Body: { "codCli": 1, "codArt": 101, "codTar": 1 }
|
tool_crear_pedido_erp |
POST /api/v1/n8n/create-order |
Inserta transaccionalmente el pedido confirmado en las tablas Pedido_Cab y Pedido_Det.Body: { "client": {...}, "items": [...], "phone": "655112233" }
|
12.5. Vinculación en UnitaGo y Depuración en Tiempo Real
Una vez levantado n8n e importado el workflow, el último paso para dejarlo 100% operativo es vincularlo en el panel administrativo de UnitaGo:
- Entra en el Panel de Administrador (
/admin) y abre la pestaña 📚 Base de Conocimiento (RAG) & n8n. - En el bloque Orquestador Cognitivo Externo (n8n Webhook):
- Marca la casilla Activar Orquestador n8n.
- En URL del Webhook de n8n indica:
https://n8n.tudominio.com/webhook/neod-copilot. - En Token Secreto del Webhook (X-Webhook-Secret) introduce vuestra clave compartida (ej.
n8n_secret_prod_unitago_2026).
- Pulsa en 💾 Guardar Configuración y seguidamente en 🧪 Probar Conexión (Ping) para verificar que UnitaGo y n8n dialogan correctamente.
-
Lanzar una prueba completa de conversación:
Podéis probar el diálogo simulado directamente desde terminal o desde la herramienta de simulación del panel:
curl -X POST http://localhost:3000/api/v1/whatsapp/simulate -H "Content-Type: application/json" -d '{"phone":"655112233","message":"Quiero pedir lo de siempre"}' - Inspección y Trazabilidad en n8n: En vuestro n8n, abrid la pestaña Executions en la barra lateral. Podréis ver cada ejecución en tiempo real, el razonamiento interno del agente de IA, qué herramientas decidió ejecutar, qué parámetros envió y qué datos devolvió MySQL.