AutomationFlowsAI & RAG › Qualify and Enrich Odoo Leads with Tavily, Google Gemini, and Resend

Qualify and Enrich Odoo Leads with Tavily, Google Gemini, and Resend

ByBitclick Solutions | B2B Engineering & Autonomous AI @bitclick on n8n.io

This workflow receives web leads via a secured webhook, enriches them with Tavily search results, scores and formats them using Google Gemini, then creates a lead in Odoo and sends a personalized email via Resend only when the lead meets the qualification threshold. Receives a…

Webhook trigger★★★★☆ complexityAI-powered23 nodesHTTP RequestOdooChain LlmGoogle Gemini ChatOutput Parser Structured
AI & RAG Trigger: Webhook Nodes: 23 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #17637 — we link there as the canonical source.

This workflow follows the Chainllm → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "G1D2LzPkoK8Xc2xo",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "[N8N] - Odoo lead clasificator enricher",
  "tags": [
    {
      "id": "xqoY4aPrfOcTOZJL",
      "name": "n8n_creators",
      "createdAt": "2026-07-21T16:01:41.443Z",
      "updatedAt": "2026-07-21T16:01:41.443Z"
    }
  ],
  "nodes": [
    {
      "id": "028bf665-c487-4f2a-9dfc-cde4c2a2f889",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        16
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## [N8N] - Odoo lead clasificator enricher clean\n\n### How it works\n\nThis workflow receives lead data through a webhook, validates the payload, and immediately returns either an acceptance or bad-request response. For valid leads, it normalizes the input, enriches the person and company using Tavily search, then sends the combined context to Gemini for structured lead classification and scoring. Based on the score threshold, it creates either a hot or cold lead in Odoo, and hot leads also trigger a Resend email notification.\n\n### Setup steps\n\n- Configure the Webhook URL and ensure incoming payloads contain the fields expected by the Validate Input and Transform Lead Data nodes.\n- Set the values in the \u2699\ufe0f Config node, especially score_threshold, company_name, company_email_from, and company_website.\n- Add valid Tavily API credentials or headers to both Tavily HTTP Request nodes.\n- Configure the Google Gemini credential/model and verify the structured output parser schema matches the fields expected by Parse Gemini Response and Score Check.\n- Connect Odoo credentials and map the hot/cold lead creation fields to your CRM pipeline requirements.\n- Configure the Resend API key, sender address, and recipient logic in the Send Email (Resend) node.\n\n### Customization\n\nAdjust the score threshold, Tavily search queries, Gemini prompt/schema, Odoo lead stages, and hot-lead email content to match your sales qualification process."
      },
      "typeVersion": 1
    },
    {
      "id": "31254025-95af-40b9-8f11-c4a8893492a7",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 512,
        "content": "## Receive and validate request\n\nHandles the incoming webhook, checks whether the payload is valid, returns a 202 response for accepted leads, or sends a bad-request response for invalid input."
      },
      "typeVersion": 1
    },
    {
      "id": "bf16f016-32a2-4328-84c4-a1661818e9ae",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1152,
        208
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 304,
        "content": "## Prepare and research lead\n\nSets workflow configuration, normalizes the lead data, and performs Tavily searches for both the person and the company to gather enrichment context."
      },
      "typeVersion": 1
    },
    {
      "id": "c4ab2ed0-3bb8-4a09-a794-b56333569df9",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 768,
        "height": 544,
        "content": "## Classify with Gemini\n\nMerges the original lead with Tavily results, sends the enriched context through a Gemini LLM chain with structured output parsing, and prepares the parsed classification result for scoring."
      },
      "typeVersion": 1
    },
    {
      "id": "974c2c76-210b-4be3-b493-afbdbb252dbd",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2848,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 512,
        "content": "## Route and create leads\n\nCompares the Gemini score against the configured threshold and creates the lead in Odoo as either hot or cold based on the scoring outcome."
      },
      "typeVersion": 1
    },
    {
      "id": "f8a33bf5-878c-453e-bba2-d7017d38c771",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3616,
        16
      ],
      "parameters": {
        "color": 7,
        "height": 368,
        "content": "## Notify hot lead\n\nSends a follow-up email through Resend when a lead is classified as hot and successfully routed through the hot Odoo branch."
      },
      "typeVersion": 1
    },
    {
      "id": "aeb4143b-f1a9-4551-82b2-6550b85bdc1f",
      "name": "Receive Webhook Data",
      "type": "n8n-nodes-base.webhook",
      "position": [
        528,
        432
      ],
      "parameters": {
        "path": "121ade20-1c34-4a4d-a509-097f2ab3a606",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode",
        "authentication": "headerAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "9ff022d0-c38b-45bc-b779-b25104d59c5c",
      "name": "Check Email Presence",
      "type": "n8n-nodes-base.if",
      "position": [
        752,
        432
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "60ce05fd-ff94-4e59-9ebc-09c058b8f7fb",
              "operator": {
                "type": "string",
                "operation": "exists"
              },
              "leftValue": "={{ $json.body.email }}",
              "rightValue": ""
            },
            {
              "id": "714cc2e5-e781-4fc2-a6af-af3e16a58d21",
              "operator": {
                "type": "string",
                "operation": "exists"
              },
              "leftValue": "={{ $json.body.name }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "549d19bb-d4ea-4d51-801a-8f023bb9e510",
      "name": "Respond with Bad Request",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        976,
        528
      ],
      "parameters": {
        "options": {
          "responseCode": 400
        },
        "respondWith": "noData"
      },
      "typeVersion": 1.4
    },
    {
      "id": "48e77ce2-f3a8-473f-9570-920eaba9de2f",
      "name": "Acknowledge with 202",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        976,
        336
      ],
      "parameters": {
        "options": {
          "responseCode": 202
        },
        "respondWith": "json",
        "responseBody": "={{ { \"status\": \"processing\", \"message\": \"Lead recibido. An\u00e1lisis de cualificaci\u00f3n en curso.\", \"timestamp\": $now } }}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "8ff30ae7-15c9-48c2-a1d8-66be15f7a850",
      "name": "Set Lead Config Parameters",
      "type": "n8n-nodes-base.set",
      "position": [
        1200,
        336
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-001",
              "name": "score_threshold",
              "type": "number",
              "value": 7
            },
            {
              "id": "cfg-002",
              "name": "company_name",
              "type": "string",
              "value": "my_company_name"
            },
            {
              "id": "cfg-003",
              "name": "company_email_from",
              "type": "string",
              "value": "my_company_email"
            },
            {
              "id": "cfg-004",
              "name": "company_website",
              "type": "string",
              "value": "my_company_domain"
            },
            {
              "id": "cfg-005",
              "name": "email_reply_to",
              "type": "string",
              "value": "my_company_reply_to_email"
            },
            {
              "id": "cfg-006",
              "name": "tavily_search_depth",
              "type": "string",
              "value": "basic"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f805fc69-4625-482b-b686-6e3f578d7b13",
      "name": "Normalize Lead Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1424,
        336
      ],
      "parameters": {
        "jsCode": "// Normaliza y estructura los datos del webhook para los nodos downstream\nconst item = $input.first().json;\nconst body = $('Receive Webhook Data').first().json.body || {};\n\n// Limpiar y parsear budget\nconst budgetRaw = body.budget || '';\nconst budget = parseFloat(budgetRaw.replace(/[^0-9.]/g, '')) || 0;\n\n// Normalizar technologies (puede llegar como array o string)\nconst technologies = Array.isArray(body.technologies)\n  ? body.technologies.join(', ')\n  : String(body.technologies || '');\n\nconst company = body.company || body.partner_name || '';\n\n// contact_name: preferir campo expl\u00edcito del formulario sobre el nombre gen\u00e9rico del lead\nconst contactName = body.contact_name || body.client_name || body.name || '';\n\n// Extraer hint de empresa desde el dominio del email cuando company est\u00e1 vac\u00edo\nconst emailRaw = body.email || '';\nconst emailDomain = emailRaw.split('@')[1] || '';\nconst domainHint = emailDomain\n  .replace(/\\.(com|es|net|org|io|eu|co\\.uk)$/i, '')\n  .trim();\nconst companyHint = company || domainHint;\n\n// \u2500\u2500 Queries Tavily optimizadas \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// query_person: nombre REAL de la persona + empresa/dominio\n// NO usar body.name (suele ser 'Cliente Web' u otro valor gen\u00e9rico del CRM)\nconst queryPerson = [contactName, companyHint]\n  .filter(s => s && s.toLowerCase() !== 'cliente web' && s.length > 1)\n  .join(' ')\n  .trim();\n\n// query_company: dominio completo para m\u00e1xima especificidad\nconst queryCompany = [emailDomain]\n  .filter(s => s && s.length > 1)\n  .join(' ')\n  .trim();\n\nreturn [{\n  json: {\n    name: body.name || '',\n    email: emailRaw,\n    email_from: emailRaw,\n    phone: body.phone || '',\n    company_domain: emailDomain,\n    company_name: companyHint,\n    contact_name: contactName,\n    description_raw: body.description || '',\n    budget: budget,\n    budget_raw: budgetRaw,\n    technologies: technologies,\n    pain: body.pain || '',\n    website: body.website || '',\n    type: 'lead',\n    planned_revenue: budget,\n    // Queries para Tavily (basadas en datos reales)\n    query_person: queryPerson,\n    query_company: queryCompany,\n    // Metadata\n    captured_at: new Date().toISOString(),\n    // Config pass-through\n    SCORE_THRESHOLD: item.SCORE_THRESHOLD,\n    STAGE_ID_NUEVO: item.STAGE_ID_NUEVO,\n    TAG_ID_CALIFICADO: item.TAG_ID_CALIFICADO,\n    TAG_ID_FRIO: item.TAG_ID_FRIO,\n    EMAIL_FROM: item.EMAIL_FROM,\n    GEMINI_MODEL: item.GEMINI_MODEL\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "6768aa02-8957-436d-ba2d-f7aa762dfbba",
      "name": "Post Tavily Person Data",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        1648,
        336
      ],
      "parameters": {
        "url": "https://api.tavily.com/search",
        "method": "POST",
        "options": {
          "timeout": 15000
        },
        "jsonBody": "={{ { \"query\": $json.query_person, \"search_depth\": $('Set Lead Config Parameters').first().json.tavily_search_depth, \"max_results\": 5, \"include_answer\": true } }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "9c166825-bfbf-4bb6-8e12-5f5cc6274259",
      "name": "Post Tavily Company Data",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        1872,
        336
      ],
      "parameters": {
        "url": "https://api.tavily.com/search",
        "method": "POST",
        "options": {
          "timeout": 15000
        },
        "jsonBody": "={{ { \"query\": $('Normalize Lead Data').first().json.query_company, \"search_depth\": $('Set Lead Config Parameters').first().json.tavily_search_depth, \"max_results\": 5, \"include_answer\": true } }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        },
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4b5b8986-bbef-4bde-8c5e-fa3461e4b845",
      "name": "Parse JSON Response",
      "type": "n8n-nodes-base.code",
      "position": [
        2672,
        336
      ],
      "parameters": {
        "jsCode": "// El parser nativo ya nos entrega el JSON listo\nconst parsed = $input.first().json;\nconst leadData = $('Merge Lead and Tavily Data').first().json;\n\nconst SCORE_THRESHOLD = leadData.SCORE_THRESHOLD || 7;\nconst score = typeof parsed.score === 'number' ? parsed.score : 0;\nconst isQualified = score >= SCORE_THRESHOLD;\n\nreturn [{\n  json: {\n    // IA Analysis\n    score: score,\n    score_rationale: parsed.score_justification || '',\n    completeness: parsed.completeness || {},\n    web_presence: parsed.enrichment || {},\n    odoo_description: parsed.odoo_description || `<p><strong>An\u00e1lisis IA (Score: ${score}/10)</strong></p>`,\n    email_subject: parsed.email_subject || `[Bitclick] Solicitud recibida \u2014 ${leadData.name}`,\n    email_body: (parsed.email_body || '').replace(/\\{nombre\\}/g, leadData.name),\n    // Routing\n    is_qualified: isQualified,\n    tag_id: isQualified ? leadData.TAG_ID_CALIFICADO : leadData.TAG_ID_FRIO,\n    tag_name: isQualified ? 'calificado' : 'fr\u00edo',\n    // Lead fields for Odoo\n    lead_name: leadData.name,\n    lead_email: leadData.email_from,\n    lead_phone: leadData.phone,\n    lead_company: leadData.company_name, // Restaurado de tu versi\u00f3n ideal\n    lead_company_domain: leadData.company_domain,\n    lead_contact_name: leadData.contact_name,\n    lead_type: leadData.type,\n    lead_planned_revenue: leadData.planned_revenue,\n    lead_stage_id: leadData.STAGE_ID_NUEVO,\n    lead_priority: parsed.priority,\n    // Email config\n    email_from_address: leadData.EMAIL_FROM\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ecf34460-5ace-4c12-bdbe-e21984d97d31",
      "name": "Evaluate Score Condition",
      "type": "n8n-nodes-base.if",
      "position": [
        2896,
        336
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "score-check-001",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.score }}",
              "rightValue": "={{ $('Set Lead Config Parameters').item.json.score_threshold}}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9fd7ea26-c4c6-44fc-a322-3d8a8a37d5c9",
      "name": "Create Odoo Lead High Priority",
      "type": "n8n-nodes-base.odoo",
      "onError": "continueErrorOutput",
      "position": [
        3200,
        240
      ],
      "parameters": {
        "resource": "custom",
        "customResource": "crm.lead",
        "fieldsToCreateOrUpdate": {
          "fields": [
            {
              "fieldName": "name",
              "fieldValue": "={{ $json.lead_contact_name }} - {{ $json.lead_company_domain }}"
            },
            {
              "fieldName": "type",
              "fieldValue": "lead"
            },
            {
              "fieldName": "contact_name",
              "fieldValue": "={{ $json.lead_contact_name }}"
            },
            {
              "fieldName": "email_from",
              "fieldValue": "={{ $json.lead_email }}"
            },
            {
              "fieldName": "phone",
              "fieldValue": "={{ $json.lead_phone }}"
            },
            {
              "fieldName": "partner_name",
              "fieldValue": "={{ $json.lead_company }}"
            },
            {
              "fieldName": "description",
              "fieldValue": "={{ $json.odoo_description }}"
            },
            {
              "fieldName": "expected_revenue",
              "fieldValue": "={{ $json.lead_planned_revenue }}"
            },
            {
              "fieldName": "priority",
              "fieldValue": "={{ $json.lead_priority.toString() }}"
            },
            {
              "fieldName": "website",
              "fieldValue": "={{ $json.lead_company_domain }}"
            }
          ]
        }
      },
      "credentials": {
        "odooApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "32cf4882-4a2f-43f0-a3c8-fd9b19d85707",
      "name": "Create Odoo Lead Low Priority",
      "type": "n8n-nodes-base.odoo",
      "onError": "continueErrorOutput",
      "position": [
        3200,
        432
      ],
      "parameters": {
        "resource": "custom",
        "customResource": "crm.lead",
        "fieldsToCreateOrUpdate": {
          "fields": [
            {
              "fieldName": "name",
              "fieldValue": "={{ $json.odoo_name }}"
            },
            {
              "fieldName": "type",
              "fieldValue": "lead"
            },
            {
              "fieldName": "contact_name",
              "fieldValue": "={{ $json.lead.contact_name }}"
            },
            {
              "fieldName": "email_from",
              "fieldValue": "={{ $json.lead.email }}"
            },
            {
              "fieldName": "phone",
              "fieldValue": "={{ $json.lead.phone }}"
            },
            {
              "fieldName": "partner_name",
              "fieldValue": "={{ $json.odoo_partner_name }}"
            },
            {
              "fieldName": "description",
              "fieldValue": "={{ $json.odoo_description }}"
            },
            {
              "fieldName": "expected_revenue",
              "fieldValue": "={{ $json.odoo_expected_revenue }}"
            },
            {
              "fieldName": "priority",
              "fieldValue": "0"
            },
            {
              "fieldName": "website",
              "fieldValue": "={{ $json.lead.website }}"
            }
          ]
        }
      },
      "credentials": {
        "odooApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fd35e8ac-6ef5-45d4-96a2-96216fa7da33",
      "name": "Chain LLM Workflow",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2320,
        336
      ],
      "parameters": {
        "text": "=Eres el motor de cualificaci\u00f3n de leads de {{$('Set Lead Config Parameters').item.json.company_name}}. Identidad operativa: \"El Arquitecto Silencioso\".\n\nTAREA: Analiza los datos del formulario web y los resultados de b\u00fasqueda (Tavily). Devuelve los datos estructurados seg\u00fan el esquema solicitado.\n\nCRITERIOS DE PUNTUACI\u00d3N (0-10):\n- Completitud (campos reales y \u00fatiles): hasta 3 puntos\n- Presencia web verificable: hasta 3 puntos\n- Alineaci\u00f3n ICP (B2B, automatizable, budget real): hasta 2 puntos\n- Urgencia del dolor operativo: hasta 2 puntos\n\nDATOS DEL FORMULARIO:\n- Nombre: {{ $json.contact_name || $json.name }}\n- Empresa: {{ $json.company_name }}\n- Tel\u00e9fono: {{ $json.phone }}\n- Email: {{ $json.email_from }}\n- Tecnolog\u00edas: {{ $json.technologies }}\n- Presupuesto: {{ $json.budget_raw }}\n- Dolor/Problema: {{ $json.pain || $json.description_raw }}\n\nRESULTADOS WEB (TAVILY):\n{{ $json.tavily_context }}\n",
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.4
    },
    {
      "id": "416e158f-0795-4147-95bd-17a28ba7b497",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        2320,
        576
      ],
      "parameters": {
        "options": {
          "temperature": 0.2
        }
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2305dd4b-498b-45af-b075-01f1dba11dfe",
      "name": "Parse Structured Output",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        2464,
        560
      ],
      "parameters": {
        "jsonSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n   \"priority\": {\"type\": \"number\", \"description\": \"El score de Odoo de 0 a 4. (0-Baja, 1-Medio, 2-Alta, 3-Muy alta) \"},\n    \"score\": { \"type\": \"number\", \"description\": \"Score del 0 al 10\" },\n    \"score_justification\": { \"type\": \"string\", \"description\": \"1-3 frases t\u00e9cnicas explicando la puntuaci\u00f3n\" },\n    \"completeness\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"has_company\": { \"type\": \"boolean\" },\n        \"has_phone\": { \"type\": \"boolean\" },\n        \"has_budget\": { \"type\": \"boolean\" },\n        \"has_technologies\": { \"type\": \"boolean\" },\n        \"has_pain_description\": { \"type\": \"boolean\" }\n      }\n    },\n    \"enrichment\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"person_found\": { \"type\": \"boolean\" },\n        \"company_verified\": { \"type\": \"boolean\" },\n        \"enrichment_summary\": { \"type\": \"string\" }\n      }\n    },\n    \"odoo_description\": { \n      \"type\": \"string\", \n      \"description\": \"HTML ultra-detallado para el campo Notas de Odoo. Usa etiquetas: <h3>, <ul>, <li>, <strong>, <p>. Muestra emojis B2B. Secciones obligatorias: 1. Origen del Lead, 2. Necesidad Detectada, 3. Stack Tecnol\u00f3gico, 4. Presupuesto Declarado, 5. Presencia Web Verificada, 6. Score IA.\" \n    },\n    \"email_subject\": { \n      \"type\": \"string\", \n      \"description\": \"Asunto exacto en formato: [Bitclick] Acci\u00f3n \u2014 Referencia\" \n    },\n    \"email_body\": { \n      \"type\": \"string\", \n      \"description\": \"Cuerpo del email en texto plano. Primera l\u00ednea exactamente: '{nombre}:'. Cuerpo: diagn\u00f3stico t\u00e9cnico conciso del problema operativo detectado + pr\u00f3ximo paso concreto (ej: llamada de diagn\u00f3stico de 30 min). Voz t\u00e9cnica B2B, sin saludos efusivos. Termina con bloque de firma:\\n--\\nBitclick Solutions SLU | Autonomous Systems & Software Engineering\\nWeb: https://bitclick.solutions\\nSoporte: user@example.com\" \n    }\n  },\n  \"required\": [\"score\", \"score_justification\", \"completeness\", \"enrichment\", \"odoo_description\", \"email_subject\", \"email_body\"]\n}"
      },
      "typeVersion": 1
    },
    {
      "id": "db3076ea-7835-4888-b56c-5a1ef391efe7",
      "name": "Merge Lead and Tavily Data",
      "type": "n8n-nodes-base.code",
      "position": [
        2096,
        336
      ],
      "parameters": {
        "jsCode": "const leadData = $('Normalize Lead Data').first().json;\nconst tavilyRaw = $input.first().json || {};\n\nconst tavilyAnswer = tavilyRaw.answer || 'Sin resultados de b\u00fasqueda disponibles.';\nconst tavilyResults = (tavilyRaw.results || [])\n  .slice(0, 5)\n  .map(r => `${r.title} - ${r.url}\\n${(r.content || '').substring(0, 300)}`)\n  .join('\\n\\n');\n\nconst tavilyContext = `Resumen: ${tavilyAnswer}\\n\\nResultados:\\n${tavilyResults || 'Ninguno'}`;\n\nreturn [{\n  json: {\n    ...leadData,\n    tavily_context: tavilyContext\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "9c11d240-278c-41a9-b37b-227afbecd8d3",
      "name": "Send Notification Email",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3664,
        224
      ],
      "parameters": {
        "url": "https://api.resend.com/emails",
        "body": "={{ JSON.stringify({\n  \"from\": $('Set Lead Config Parameters').item.json.email_reply_to,\n  \"to\": [$('Parse JSON Response').item.json.lead_email],\n  \"subject\": $('Parse JSON Response').item.json.email_subject,\n  \"text\": $('Parse JSON Response').item.json.email_body\n}) }}",
        "method": "POST",
        "options": {
          "timeout": 10000
        },
        "sendBody": true,
        "contentType": "raw",
        "authentication": "genericCredentialType",
        "rawContentType": "application/json",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "05cce173-ed74-4b47-bd46-2f3f16ca376b",
  "nodeGroups": [],
  "connections": {
    "Chain LLM Workflow": {
      "main": [
        [
          {
            "node": "Parse JSON Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Lead Data": {
      "main": [
        [
          {
            "node": "Post Tavily Person Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse JSON Response": {
      "main": [
        [
          {
            "node": "Evaluate Score Condition",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Acknowledge with 202": {
      "main": [
        [
          {
            "node": "Set Lead Config Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Email Presence": {
      "main": [
        [
          {
            "node": "Acknowledge with 202",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond with Bad Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Webhook Data": {
      "main": [
        [
          {
            "node": "Check Email Presence",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Structured Output": {
      "ai_outputParser": [
        [
          {
            "node": "Chain LLM Workflow",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Post Tavily Person Data": {
      "main": [
        [
          {
            "node": "Post Tavily Company Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Post Tavily Company Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Score Condition": {
      "main": [
        [
          {
            "node": "Create Odoo Lead High Priority",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create Odoo Lead Low Priority",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Chain LLM Workflow",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Post Tavily Company Data": {
      "main": [
        [
          {
            "node": "Merge Lead and Tavily Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge Lead and Tavily Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Lead and Tavily Data": {
      "main": [
        [
          {
            "node": "Chain LLM Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Lead Config Parameters": {
      "main": [
        [
          {
            "node": "Normalize Lead Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Odoo Lead High Priority": {
      "main": [
        [
          {
            "node": "Send Notification Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow receives web leads via a secured webhook, enriches them with Tavily search results, scores and formats them using Google Gemini, then creates a lead in Odoo and sends a personalized email via Resend only when the lead meets the qualification threshold. Receives a…

Source: https://n8n.io/workflows/17637/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Resume Screening & Behavioral Interviews with Gemini, Elevenlabs, & Notion ATS copy. Uses outputParserStructured, chainLlm, googleDrive, stickyNote. Webhook trigger; 67 nodes.

Output Parser Structured, Chain Llm, Google Drive +9
AI & RAG

Candidate Engagement | Resume Screening | AI Voice Interviews | Applicant Insights

Output Parser Structured, Chain Llm, Google Drive +9
AI & RAG

leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.

Supabase, Gmail, Form Trigger +13
AI & RAG

This workflow acts as an AI-powered research assistant that takes a topic from the user, performs multi-step intelligent research, and stores the final report in Notion. It uses advanced search, conte

Memory Buffer Window, Output Parser Structured, Agent +6
AI & RAG

Categories: Accounting Automation • OCR Processing • AI Data Extraction • Business Tools

HTTP Request, OpenRouter Chat, Google Gemini Chat +4