{
  "name": "Logixb2b — Listas leads B2B cualificados (juez ICP)",
  "meta": {
    "templateCredsSetupCompleted": false,
    "description": "Manual Trigger → Config Listas ICP/CRM → Payload de prueba (5 leads brutos) → Limitar lote maxBatch → Juez ICP lista (score) → IF entra en lista → Upsert HubSpot/Pipedrive + Sheets + Slack | Skip + Sheets reject. Europe/Madrid. Placeholders REEMPLAZA_*."
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Europe/Madrid"
  },
  "active": false,
  "pinData": {},
  "tags": [
    { "name": "Logixb2b" },
    { "name": "recursos" },
    { "name": "prospeccion" }
  ],
  "nodes": [
    {
      "id": "sticky-instrucciones-listas",
      "name": "INSTRUCCIONES (conectar + VPS)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-520, 20],
      "parameters": {
        "content": "## INSTRUCCIONES — Listas leads B2B cualificados (juez ICP)\n\n**Recurso:** `/recursos/listas-leads-b2b-ia-n8n`\n**Guía:** /como-construir-listas-leads-b2b-cualificados-con-ia\n**Zona:** Europe/Madrid · `active: false` al importar (tú lo activas).\n\n### 1) Importar\n1. n8n → ⋯ → **Import from File** → este JSON.\n2. El flujo llega **inactive**. No pegues secretos en el lienzo ni en el archivo.\n\n### 2) Credenciales y configuración por nodo\n- **Manual Trigger listas** (`manual`): sin credencial. Pruebas; en producción → Webhook / Schedule / lectura Sheets.\n- **Config Listas ICP/CRM** (`Set`): **sin credencial**. Aquí van `crmProvider`, tokens HubSpot/Pipedrive (`REEMPLAZA_*`), umbral, CSV de cargos/sectores/exclusiones, banda de empleados, `listName`, `maxBatchPerRun`, Sheets y Slack.\n- **Payload de prueba (5 leads brutos)** (`Code`): sin credencial. 5 filas @example.com con distinto encaje ICP. Sustituye por tu fuente real.\n- **Limitar lote (maxBatch)** (`Code`): sin credencial. Recorta el lote al techo diario/ejecución.\n- **Juez ICP lista (score)** (`Code`): sin credencial. Puntúa email, cargo, sector, país UE, tamaño empresa, señales de compra y exclusiones. Ajusta pesos en el JS.\n- **IF entra en lista cualificada** (`IF`): sin credencial. `qualified === true`.\n- **Upsert Lead CRM (HubSpot/Pipedrive)** (`HTTP`): Credentials → Header Auth / Bearer. Elige proveedor con `crmProvider`.\n- **Append Sheets (lista OK)** / **Append Sheets (fuera ICP)**: Google Sheets OAuth2. Pestaña `Listas_ICP`.\n- **Slack resumen lista**: Incoming Webhook. URL en Config.\n- **Skip fuera de ICP** (`NoOp`): rama trazable; el log de rechazo ya va a Sheets.\n\n### 3) Orden de puesta en marcha\n1. Rellena **Config** (ICP, umbral, listName, crmProvider).\n2. Crea Credentials (CRM, Sheets, Slack) y enlázalas.\n3. Ejecuta **una vez** con Manual Trigger: verás 2–3 qualified y el resto en fuera ICP.\n4. Revisa CRM + Sheets + Slack. **HITL** antes de meter la lista en outbound.\n5. Solo entonces: **Active**.\n\n### 4) Producción 24/7 en VPS (UE)\n1. VPS UE + Docker Compose + Postgres + HTTPS.\n2. `GENERIC_TIMEZONE=Europe/Madrid`, `WEBHOOK_URL`, `N8N_ENCRYPTION_KEY`.\n3. Firewall 80/443 (+ SSH). Backups Postgres + export workflows.\n4. Importa en producción, recrea Credentials, URLs reales.\n5. Sustituye el Payload de prueba por Webhook/Sheets con leads brutos. Respeta `maxBatchPerRun`.\n6. Alternativa: n8n Cloud.\n\n### 5) RGPD + EU AI Act\nTratas datos de contacto B2B: documenta interés legítimo, minimiza campos, marca `complianceFlag`. Si sustituyes el juez por LLM sois **deployers** (Reglamento UE 2024/1689 Art. 4). **HITL** antes de outreach. Informativo — no es asesoramiento legal. /uso-responsable-de-ia-y-transparencia\n",
        "height": 1680,
        "width": 600,
        "color": 4
      }
    },
    {
      "id": "ll-trigger",
      "name": "Manual Trigger listas",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [0, 360],
      "parameters": {}
    },
    {
      "id": "ll-config",
      "name": "Config Listas ICP/CRM",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [260, 360],
      "parameters": {
        "mode": "manual",
        "duplicateItem": false,
        "assignments": {
          "assignments": [
            { "id": "a1", "name": "crmProvider", "value": "hubspot", "type": "string" },
            { "id": "a2", "name": "crmBaseUrl", "value": "https://api.hubapi.com", "type": "string" },
            { "id": "a3", "name": "crmToken", "value": "REEMPLAZA_HUBSPOT_TOKEN", "type": "string" },
            { "id": "a4", "name": "pipedriveBaseUrl", "value": "https://REEMPLAZA_TU_EMPRESA.pipedrive.com/api/v1", "type": "string" },
            { "id": "a5", "name": "pipedriveApiToken", "value": "REEMPLAZA_PIPEDRIVE_API_TOKEN", "type": "string" },
            { "id": "a6", "name": "listName", "value": "lista_icp_cualificada_es_2026", "type": "string" },
            { "id": "a7", "name": "scoreThreshold", "value": "65", "type": "string" },
            { "id": "a8", "name": "icpTitles", "value": "ceo,cto,coo,founder,fundador,head of sales,director comercial,revops,revenue operations,vp sales", "type": "string" },
            { "id": "a9", "name": "icpSectors", "value": "saas,software,logistica,logística,b2b,revops,industrial", "type": "string" },
            { "id": "a10", "name": "excludeTitles", "value": "becario,intern,estudiante,auxiliar,prácticas,practicas", "type": "string" },
            { "id": "a11", "name": "minEmployees", "value": "10", "type": "string" },
            { "id": "a12", "name": "maxEmployees", "value": "2000", "type": "string" },
            { "id": "a13", "name": "requireEmailOk", "value": "true", "type": "string" },
            { "id": "a14", "name": "maxBatchPerRun", "value": "40", "type": "string" },
            { "id": "a15", "name": "sheetsId", "value": "REEMPLAZA_SHEETS_ID", "type": "string" },
            { "id": "a16", "name": "slackWebhookUrl", "value": "https://hooks.example.com/services/REEMPLAZA_SLACK", "type": "string" },
            { "id": "a17", "name": "batchLabel", "value": "listas-icp-demo-2026-08", "type": "string" },
            { "id": "a18", "name": "timezone", "value": "Europe/Madrid", "type": "string" }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "ll-sample",
      "name": "Payload de prueba (5 leads brutos)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [540, 360],
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const cfg = $('Config Listas ICP/CRM').first().json;\nconst sample = [\n  {\n    firstName: 'Lucía',\n    lastName: 'Vega',\n    email: 'lucia.vega@nortecloud-example.es',\n    title: 'CEO',\n    company: 'NorteCloud SaaS SL',\n    sector: 'SaaS B2B',\n    country: 'España',\n    employees: 38,\n    signals: 'Serie A 2025; contratando SDR; stack HubSpot',\n    source: 'export_manual'\n  },\n  {\n    firstName: 'Diego',\n    lastName: 'Ferrer',\n    email: 'diego.ferrer@iberruta-example.es',\n    title: 'Head of Sales',\n    company: 'IberRuta Logística',\n    sector: 'Logística B2B',\n    country: 'España',\n    employees: 210,\n    signals: 'nuevo hub Madrid; expansión flota UE',\n    source: 'apollo_csv'\n  },\n  {\n    firstName: 'Nora',\n    lastName: 'Sanz',\n    email: 'nora.sanz@retailnorte-example.com',\n    title: 'Marketing Intern',\n    company: 'Retail Norte SA',\n    sector: 'Retail B2C',\n    country: 'United States',\n    employees: 900,\n    signals: 'newsletter B2C; sin intención compra software',\n    source: 'lista_comprada'\n  },\n  {\n    firstName: 'Hugo',\n    lastName: 'Mena',\n    email: 'hugo.mena@uni-example.es',\n    title: 'Estudiante de ADE',\n    company: 'Universidad Demo',\n    sector: 'Educación',\n    country: 'España',\n    employees: 1,\n    signals: 'sin presupuesto comercial',\n    source: 'evento_networking'\n  },\n  {\n    firstName: 'Irene',\n    lastName: 'Costa',\n    email: 'irene.costa@vertice-example.pt',\n    title: 'Director Comercial',\n    company: 'Vértice Industrial PT',\n    sector: 'Industrial B2B',\n    country: 'Portugal',\n    employees: 95,\n    signals: 'RFP automatización CRM; cambio ERP 2026',\n    source: 'referral_partner'\n  }\n];\nreturn sample.map((row) => ({ json: { ...row, crmProvider: cfg.crmProvider } }));"
      }
    },
    {
      "id": "ll-batch",
      "name": "Limitar lote (maxBatch)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [800, 360],
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const cfg = $('Config Listas ICP/CRM').first().json;\nconst maxBatch = Math.max(1, Number(cfg.maxBatchPerRun) || 40);\nconst items = $input.all();\nconst sliced = items.slice(0, maxBatch);\nconst truncated = items.length > maxBatch;\nreturn sliced.map((it, idx) => ({\n  json: {\n    ...it.json,\n    _batchIndex: idx + 1,\n    _batchTotalIn: items.length,\n    _batchKept: sliced.length,\n    _batchTruncated: truncated\n  }\n}));"
      }
    },
    {
      "id": "ll-judge",
      "name": "Juez ICP lista (score)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1060, 360],
      "parameters": {
        "mode": "runOnceForEachItem",
        "language": "javaScript",
        "jsCode": "const cfg = $('Config Listas ICP/CRM').first().json;\nconst splitCsv = (s) => String(s || '').split(',').map((x) => x.trim().toLowerCase()).filter(Boolean);\nconst titles = splitCsv(cfg.icpTitles);\nconst sectors = splitCsv(cfg.icpSectors);\nconst excludes = splitCsv(cfg.excludeTitles);\nconst minEmp = Number(cfg.minEmployees) || 10;\nconst maxEmp = Number(cfg.maxEmployees) || 2000;\nconst threshold = Number(cfg.scoreThreshold) || 65;\nconst requireEmail = String(cfg.requireEmailOk) !== 'false';\n\nconst euMap = {\n  'españa': 'ES', spain: 'ES', es: 'ES',\n  portugal: 'PT', pt: 'PT',\n  francia: 'FR', france: 'FR', fr: 'FR',\n  alemania: 'DE', germany: 'DE', de: 'DE',\n  italia: 'IT', italy: 'IT', it: 'IT',\n  'países bajos': 'NL', netherlands: 'NL', nl: 'NL',\n  belgica: 'BE', belgium: 'BE', be: 'BE'\n};\n\nconst p = item.json || {};\nconst email = String(p.email || '').toLowerCase().trim();\nconst emailOk = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\nconst title = String(p.title || '').toLowerCase();\nconst sector = String(p.sector || '').toLowerCase();\nconst countryRaw = String(p.country || '').toLowerCase().trim();\nconst countryCode = euMap[countryRaw] || String(p.country || '').toUpperCase().slice(0, 2);\nconst isEu = Boolean(euMap[countryRaw]) || ['ES','PT','FR','DE','IT','NL','BE'].includes(countryCode);\nconst employees = Number(p.employees) || 0;\nconst signals = String(p.signals || '').toLowerCase();\n\nconst reasons = [];\nlet score = 0;\n\nif (emailOk) { score += 15; reasons.push('email_ok'); }\nelse { reasons.push('email_invalido'); }\n\nconst excluded = excludes.some((ex) => title.includes(ex));\nif (excluded) { reasons.push('titulo_excluido'); }\n\nconst titleHit = !excluded && titles.some((t) => title.includes(t));\nif (titleHit) { score += 30; reasons.push('cargo_icp'); }\n\nconst sectorHit = sectors.some((s) => sector.includes(s));\nif (sectorHit) { score += 20; reasons.push('sector_icp'); }\n\nif (isEu) { score += 15; reasons.push('pais_ue'); }\nelse { reasons.push('pais_fuera_ue'); }\n\nconst sizeOk = employees >= minEmp && employees <= maxEmp;\nif (sizeOk) { score += 10; reasons.push('tamano_ok'); }\nelse { reasons.push('tamano_fuera_banda'); }\n\nif (/(serie\\s?[abc]|contrat|hiring|sdr|rfp|erp|hubspot|pipedrive|expans|financi)/.test(signals)) {\n  score += 10;\n  reasons.push('senal_compra');\n}\n\nscore = Math.max(0, Math.min(100, score));\nif (excluded) score = Math.min(score, 25);\n\nconst qualified = (!requireEmail || emailOk) && !excluded && score >= threshold && sizeOk && isEu;\nconst complianceFlag = isEu\n  ? 'ok_ue_minimizar_datos_hitl_antes_outreach'\n  : 'revisar_base_juridica_extra_ue';\n\nreturn {\n  json: {\n    batchLabel: cfg.batchLabel,\n    listName: cfg.listName,\n    crmProvider: cfg.crmProvider,\n    crmBaseUrl: cfg.crmBaseUrl,\n    crmToken: cfg.crmToken,\n    pipedriveBaseUrl: cfg.pipedriveBaseUrl,\n    pipedriveApiToken: cfg.pipedriveApiToken,\n    sheetsId: cfg.sheetsId,\n    slackWebhookUrl: cfg.slackWebhookUrl,\n    timezone: cfg.timezone || 'Europe/Madrid',\n    firstName: p.firstName || '',\n    lastName: p.lastName || '',\n    email,\n    emailOk,\n    title: p.title || '',\n    company: p.company || '',\n    sector: p.sector || '',\n    country: p.country || '',\n    countryCode,\n    employees,\n    signals: p.signals || '',\n    source: p.source || 'unknown',\n    icpScore: score,\n    icpReasons: reasons.join('|'),\n    qualified,\n    scoreThreshold: threshold,\n    complianceFlag,\n    _batchIndex: p._batchIndex,\n    _batchKept: p._batchKept,\n    _batchTruncated: p._batchTruncated\n  }\n};"
      }
    },
    {
      "id": "ll-if",
      "name": "IF entra en lista cualificada",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1320, 360],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "q1",
              "leftValue": "={{ $json.qualified }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "ll-upsert",
      "name": "Upsert Lead CRM (HubSpot/Pipedrive)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1600, 220],
      "parameters": {
        "method": "POST",
        "url": "={{ $json.crmProvider === 'pipedrive' ? ($json.pipedriveBaseUrl + '/persons?api_token=' + $json.pipedriveApiToken) : ($json.crmBaseUrl + '/crm/v3/objects/contacts/batch/upsert') }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ $json.crmProvider === 'pipedrive' ? '' : 'Bearer ' + $json.crmToken }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.crmProvider === 'pipedrive' ? { name: ($json.firstName + ' ' + $json.lastName).trim(), email: [{ value: $json.email, primary: true }], org_name: $json.company, visible_to: '3' } : { inputs: [{ idProperty: 'email', id: $json.email, properties: { email: $json.email, firstname: $json.firstName, lastname: $json.lastName, company: $json.company, jobtitle: $json.title, hs_lead_status: 'NEW', lista_icp_nombre: $json.listName, icp_score: String($json.icpScore), icp_reasons: $json.icpReasons, lead_source_list_builder: $json.source } }] }) }}",
        "options": { "timeout": 30000 }
      }
    },
    {
      "id": "ll-sheets-ok",
      "name": "Append Sheets (lista OK)",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [1880, 220],
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "={{ $('Config Listas ICP/CRM').item.json.sheetsId }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Listas_ICP",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "fecha": "={{ $now.setZone('Europe/Madrid').toFormat('yyyy-MM-dd HH:mm') }}",
            "batchLabel": "={{ $('Juez ICP lista (score)').item.json.batchLabel }}",
            "listName": "={{ $('Juez ICP lista (score)').item.json.listName }}",
            "company": "={{ $('Juez ICP lista (score)').item.json.company }}",
            "email": "={{ $('Juez ICP lista (score)').item.json.email }}",
            "title": "={{ $('Juez ICP lista (score)').item.json.title }}",
            "sector": "={{ $('Juez ICP lista (score)').item.json.sector }}",
            "country": "={{ $('Juez ICP lista (score)').item.json.country }}",
            "icpScore": "={{ $('Juez ICP lista (score)').item.json.icpScore }}",
            "icpReasons": "={{ $('Juez ICP lista (score)').item.json.icpReasons }}",
            "complianceFlag": "={{ $('Juez ICP lista (score)').item.json.complianceFlag }}",
            "crmProvider": "={{ $('Juez ICP lista (score)').item.json.crmProvider }}",
            "estado": "lista_cualificada"
          }
        },
        "options": {}
      }
    },
    {
      "id": "ll-slack",
      "name": "Slack resumen lista",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [2160, 220],
      "parameters": {
        "method": "POST",
        "url": "={{ $('Juez ICP lista (score)').item.json.slackWebhookUrl }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ text: '[Logixb2b Listas ICP] ' + $('Juez ICP lista (score)').item.json.listName + ' · ' + $('Juez ICP lista (score)').item.json.company + ' (' + $('Juez ICP lista (score)').item.json.email + ') score ' + $('Juez ICP lista (score)').item.json.icpScore + ' → ' + $('Juez ICP lista (score)').item.json.crmProvider + ' · ' + $('Juez ICP lista (score)').item.json.icpReasons + ' · ' + $('Juez ICP lista (score)').item.json.complianceFlag }) }}",
        "options": {
          "timeout": 15000,
          "response": {
            "response": { "neverError": true }
          }
        }
      }
    },
    {
      "id": "ll-skip",
      "name": "Skip fuera de ICP",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [1600, 520],
      "parameters": {}
    },
    {
      "id": "ll-sheets-reject",
      "name": "Append Sheets (fuera ICP)",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [1880, 520],
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "={{ $('Config Listas ICP/CRM').item.json.sheetsId }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Listas_ICP",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "fecha": "={{ $now.setZone('Europe/Madrid').toFormat('yyyy-MM-dd HH:mm') }}",
            "batchLabel": "={{ $('Juez ICP lista (score)').item.json.batchLabel }}",
            "listName": "={{ $('Juez ICP lista (score)').item.json.listName }}",
            "company": "={{ $('Juez ICP lista (score)').item.json.company }}",
            "email": "={{ $('Juez ICP lista (score)').item.json.email }}",
            "title": "={{ $('Juez ICP lista (score)').item.json.title }}",
            "sector": "={{ $('Juez ICP lista (score)').item.json.sector }}",
            "country": "={{ $('Juez ICP lista (score)').item.json.country }}",
            "icpScore": "={{ $('Juez ICP lista (score)').item.json.icpScore }}",
            "icpReasons": "={{ $('Juez ICP lista (score)').item.json.icpReasons }}",
            "complianceFlag": "={{ $('Juez ICP lista (score)').item.json.complianceFlag }}",
            "crmProvider": "={{ $('Juez ICP lista (score)').item.json.crmProvider }}",
            "estado": "fuera_icp"
          }
        },
        "options": {}
      }
    }
  ],
  "connections": {
    "Manual Trigger listas": {
      "main": [[{ "node": "Config Listas ICP/CRM", "type": "main", "index": 0 }]]
    },
    "Config Listas ICP/CRM": {
      "main": [[{ "node": "Payload de prueba (5 leads brutos)", "type": "main", "index": 0 }]]
    },
    "Payload de prueba (5 leads brutos)": {
      "main": [[{ "node": "Limitar lote (maxBatch)", "type": "main", "index": 0 }]]
    },
    "Limitar lote (maxBatch)": {
      "main": [[{ "node": "Juez ICP lista (score)", "type": "main", "index": 0 }]]
    },
    "Juez ICP lista (score)": {
      "main": [[{ "node": "IF entra en lista cualificada", "type": "main", "index": 0 }]]
    },
    "IF entra en lista cualificada": {
      "main": [
        [{ "node": "Upsert Lead CRM (HubSpot/Pipedrive)", "type": "main", "index": 0 }],
        [{ "node": "Skip fuera de ICP", "type": "main", "index": 0 }]
      ]
    },
    "Upsert Lead CRM (HubSpot/Pipedrive)": {
      "main": [[{ "node": "Append Sheets (lista OK)", "type": "main", "index": 0 }]]
    },
    "Append Sheets (lista OK)": {
      "main": [[{ "node": "Slack resumen lista", "type": "main", "index": 0 }]]
    },
    "Skip fuera de ICP": {
      "main": [[{ "node": "Append Sheets (fuera ICP)", "type": "main", "index": 0 }]]
    }
  }
}
