⚡
UnitaGo API Docs
Guía de Integración Interna para el ERP
Administrador
🖨️ Escáner ⚙️ Panel Admin

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.

📄 Extracción Contable de Facturas (Visión IA)

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.

💬 Bot Comercial WhatsApp & Pedidos ERP

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 de Deuda & Pasarela Redsys

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).

🧠 RAG Semántico y Orquestación n8n

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.

🏢 Arquitectura Multi-Tenant & Panel de Control Global

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.

⚡ Filosofía de Integración: Una sola API REST estándar, segura y documentada para conectar Delphi, C#, PHP, Python o scripts de terminal con toda la potencia de la inteligencia artificial, sin modificar la estructura nuclear de vuestro ERP.

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>):

X-API-Key: ndg_live_demo_1234567890abcdef1234567890abcdef
💡 Guía Neo: Cada empresa registrada dispone de su propia clave privada. Podéis consultar o regenerar los tokens API en cualquier momento desde el Panel de Administración > Empresas o copiar vuestro token activo en el Portal Escáner.

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)

POST /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:

Respuesta JSON Estándar (Facturas y Albaranes)
{
  "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

GET /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_...
Respuesta JSON
{
  "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

GET /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.

Respuesta JSON
{
  "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

POST /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

GET /health

Endpoint público de diagnóstico para monitorización de uptime y comprobación de la conexión con MySQL.

Respuesta JSON
{
  "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_socialStringNombre comercial o razón social completa.
cif_nifStringNIF/CIF español o VAT number europeo (sin guiones extraños).
direccionStringDirección fiscal o sede del proveedor/cliente.
codigo_postalStringCódigo postal si está presente en el membrete.
poblacionStringCiudad / municipio.
paisStringCódigo ISO 2 letras (ej: ES, FR, DE).
ibanStringCó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_ivaNumberPorcentaje aplicado (21, 10, 4, 0).
base_imponibleNumberBase imponible correspondiente a ese tipo de gravamen.
cuota_ivaNumberCuota de IVA calculada (base * tipo / 100).
recargo_equivalenciaNumberRecargo 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
aplicaBooleantrue si la factura tiene retención de IRPF, false si no.
porcentajeNumberPorcentaje de retención (ej: 15.00).
importe_retenidoNumberImporte total retenido a restar del pago.

9.3 Líneas de Detalle (Artículos / Servicios)

Campo Tipo Descripción
descripcionStringConcepto o descripción del artículo o servicio.
referenciaString / nullCódigo de referencia, SKU o código de proveedor.
cantidadNumberUnidades facturadas (por defecto 1).
precio_unitarioNumberPrecio por unidad sin impuestos.
descuento_porcentajeNumberDescuento comercial por línea si aplica (0 a 100).
tipo_ivaNumberTipo de IVA de esta línea específica.
importe_lineaNumberImporte neto total de la línea.

10. Ejemplos de Implementación en el ERP

⭐ Entorno Oficial del ERP: Embarcadero Delphi (Object Pascal)

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)

  1. 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?").
  2. 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.
  3. 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-copilot transmitiendo el mensaje del usuario, sessionId, clientId, el nombre del cliente y su teléfono.
  4. 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.
  5. 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_precio o inserción de pedidos en Pedido_Cab y Pedido_Det.
  6. Respuesta Estructurada: n8n genera la respuesta final y la devuelve a UnitaGo en formato JSON estructurado: { "reply": "...", "provider": "n8n", "sources": [...] }.
  7. Entrega al Cliente: UnitaGo formatea y entrega el mensaje final al cliente en WhatsApp o en la interfaz web de Neo Copilot.
🛡️ Tolerancia a Fallos y Conmutación Automática (Failover): Si en algún momento el contenedor de n8n se detiene por mantenimiento, la red del VPS sufre un microcorte o el webhook excede el tiempo límite (timeout), UnitaGo conmuta automáticamente al motor conversacional nativo en milisegundos. Vuestros clientes nunca verán un error ni se quedarán sin respuesta.

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.

📦 Plantilla de Flujo: neod_copilot_workflow_n8n.json
Incluye Webhook de entrada, AI Agent (LangChain), Buffer Memory, 5 herramientas HTTP parametrizadas y nodo de respuesta.
📥 Descargar Workflow Oficial (.json)

Pasos para importarlo en vuestro n8n:

  1. Accede a vuestro panel de n8n (ej. https://n8n.tudominio.com).
  2. En el menú lateral izquierdo, pulsa en Workflows y luego en + Add Workflow.
  3. En la esquina superior derecha del lienzo, haz clic en el botón de tres puntos (...) y selecciona Import from File.
  4. Selecciona el archivo descargado neod_copilot_workflow_n8n.json. ¡Todo el flujo aparecerá instantáneamente conectado!
  5. 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.
  6. 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:

  1. Entra en el Panel de Administrador (/admin) y abre la pestaña 📚 Base de Conocimiento (RAG) & n8n.
  2. 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).
  3. Pulsa en 💾 Guardar Configuración y seguidamente en 🧪 Probar Conexión (Ping) para verificar que UnitaGo y n8n dialogan correctamente.
  4. 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"}'
  5. 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.
✅ Copiado al portapapeles