{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "aff89a96-bcc9-42b8-a000-2ff49d25876f",
      "name": "Note \u2014 Stage 2b",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6080,
        960
      ],
      "parameters": {
        "color": 4,
        "width": 516,
        "height": 520,
        "content": "## \ud83e\udd16 Stage 2b \u2014 AI Field Extraction\n\nSends the **raw webhook payload** to GPT-4o-mini via OpenRouter.  \nThe AI automatically detects and extracts lead fields from any source system, regardless of naming conventions or payload structure.\n\nAI-extracted values are merged with the Normalize output:\n- AI values are prioritized when available\n- Normalize values are used as fallback\n\n\u26a0\ufe0f Uses the same OpenRouter credentials as Stage 4.\n\n### \ud83d\udd11 OpenRouter Credentials Setup\n\n1. Create an account at `https://openrouter.ai`\n2. Generate an API key from the OpenRouter dashboard\n3. In n8n, create a new credential:\n   - **Credential Type:** Header Auth\n   - **Name:** `Header Auth OpenRouter`\n4. Configure it like this:\n\n| Field | Value |\n|---|---|\n| Name  | `Authorization` |\n| Value  | `Bearer YOUR_OPENROUTER_API_KEY` |\n\n5. Attach this credential to both:\n- Stage 2b \u2014 AI Field Extraction\n- Stage 4 \u2014 AI BANT Scoring"
      },
      "typeVersion": 1
    },
    {
      "id": "a94344c2-abf3-4503-af93-49079930f010",
      "name": "Build extraction prompt",
      "type": "n8n-nodes-base.set",
      "position": [
        -6080,
        1504
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ep01",
              "name": "raw_payload",
              "type": "string",
              "value": "={{ JSON.stringify($node['Lead entry webhook'].json.body !== undefined ? $node['Lead entry webhook'].json.body : $node['Lead entry webhook'].json) }}"
            },
            {
              "id": "ep02",
              "name": "extract_system_prompt",
              "type": "string",
              "value": "You are a contact data extraction assistant. Extract structured contact information from the JSON payload. The payload may use any field naming convention.\n\nReturn ONLY a valid JSON object \u2014 no prose, no markdown fences, no code blocks.\n\nJSON shape:\n{\"first_name\": string, \"last_name\": string, \"email\": string, \"company\": string, \"job_title\": string, \"phone\": string, \"message\": string, \"source\": string}\n\nExtraction rules:\nfirst_name: first_name, fname, given_name, forename, first, or first word of name/full_name/display_name\nlast_name: last_name, lname, surname, family_name, last, or remaining words of name/full_name\nemail: email, email_address, contact_email, mail, e_mail \u2014 or any value containing '@'\ncompany: company, organization, organisation, org, company_name, employer, business, firm, account\njob_title: job_title, title, role, position, designation, occupation, job_role\nphone: phone, phone_number, mobile, cell, contact_number, tel, telephone, work_phone\nmessage: message, notes, note, comment, description, inquiry, enquiry, body, content, question, request, how_can_we_help\nsource: source, utm_source, referral, channel, lead_source \u2014 default to 'webhook' if not found\n\nNormalization: email always lowercase and trimmed. Names trimmed. Empty string if field not found.\nReturn nothing except the JSON object."
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "c951dcdc-4246-4c26-8431-16e37d8c317b",
      "name": "AI extract fields",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -5840,
        1504
      ],
      "parameters": {
        "url": "https://openrouter.ai/api/v1/chat/completions",
        "body": "={{ JSON.stringify({ model: 'openai/gpt-4o-mini', temperature: 0, max_tokens: 300, messages: [{ role: 'system', content: $json.extract_system_prompt }, { role: 'user', content: $json.raw_payload }] }) }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "rawContentType": "application/json",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b82e62a2-bf4b-4f27-8455-1a3179e3bdd0",
      "name": "Parse extracted fields",
      "type": "n8n-nodes-base.code",
      "position": [
        -5600,
        1504
      ],
      "parameters": {
        "jsCode": "const aiRaw = items[0].json.choices?.[0]?.message?.content || '{}';\nconst cleaned = aiRaw.replace(/```json|```/g, '').trim();\nlet parsed = {};\ntry {\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  // regex fallback\n  const get = (key) => {\n    const m = aiRaw.match(new RegExp('\"' + key + '\"\\\\s*:\\\\s*\"([^\"]*?)\"', 'i'));\n    return m ? m[1].trim() : '';\n  };\n  parsed = {\n    first_name: get('first_name'), last_name: get('last_name'),\n    email: get('email'), company: get('company'),\n    job_title: get('job_title'), phone: get('phone'),\n    message: get('message'), source: get('source')\n  };\n}\n\n// Merge: AI values take priority over Normalize, Normalize used as fallback\nconst norm = $('Normalize lead fields').first().json;\nconst pick = (ai, fb) => ((ai || '').trim()) || ((fb || '').trim());\n\nreturn [{\n  json: {\n    ...norm,\n    first_name  : pick(parsed.first_name,  norm.first_name),\n    last_name   : pick(parsed.last_name,   norm.last_name),\n    email       : (parsed.email || norm.email || '').toLowerCase().trim(),\n    company     : pick(parsed.company,     norm.company),\n    job_title   : pick(parsed.job_title,   norm.job_title),\n    phone       : pick(parsed.phone,       norm.phone),\n    message     : pick(parsed.message,     norm.message),\n    source      : pick(parsed.source,      norm.source) || 'webhook',\n    submitted_at: norm.submitted_at || new Date().toISOString(),\n    _ai_extracted: Object.keys(parsed).some(k => parsed[k])\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "8b7d163e-531f-4f03-8e7f-775439c27780",
      "name": "Note \u2014 Hunter",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5136,
        880
      ],
      "parameters": {
        "color": 6,
        "width": 484,
        "height": 604,
        "content": "## \ud83d\udd0e Stage 3b \u2014 Hunter.io Enrichment\n\nUses the lead\u2019s email domain to enrich company data including:\n- Company name\n- Industry\n- Employee size\n- Country\n\nIf the domain is personal (Gmail, Yahoo, Outlook, etc.) or unknown, Hunter may return no data \u2014 the workflow continues gracefully using existing enriched values.\n\n\u26a0\ufe0f Uses your Hunter.io API key.\n\n### \ud83d\udd11 Hunter.io API Setup\n\n1. Create an account at `https://hunter.io`\n2. Generate your API key from the Hunter dashboard\n3. In n8n, create a new credential:\n   - **Credential Type:** Header Auth\n   - **Name:** `Header Auth Hunter`\n\n4. Configure it like this:\n\n| Field | Value |\n|---|---|\n| Name |  ` api_key` |\n| Value |  ` YOUR_HUNTER_API_KEY` |\n\n5. Attach this credential to the Hunter.io enrichment node.\n\n### \ud83d\udcb3 Hunter.io Pricing\n- Free plan \u2192 25 requests/month\n- Paid plans \u2192 Starting from $34/month"
      },
      "typeVersion": 1
    },
    {
      "id": "3df4f022-f8fc-425e-b05d-4540e3180869",
      "name": "Hunter.io domain search",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -5120,
        1504
      ],
      "parameters": {
        "url": "https://api.hunter.io/v2/domain-search",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "domain",
              "value": "={{ $json.domain }}"
            },
            {
              "name": "limit",
              "value": "1"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "55520e4f-8318-474c-9773-37dcc82c79fb",
      "name": "Parse Hunter response",
      "type": "n8n-nodes-base.code",
      "position": [
        -4880,
        1504
      ],
      "parameters": {
        "jsCode": "const hunterResp = items[0].json;\n// Get the full lead data from the previous enrichment step\nconst lead = $('Enrich from email domain').first().json;\n\n// Safely extract Hunter data \u2014 handles errors / empty responses gracefully\nconst d = (hunterResp.data) || {};\nconst hunterCompany   = (d.organization || '').trim();\nconst hunterIndustry  = (d.industry     || '').trim();\nconst hunterSize      = d.size          || '';\nconst hunterCountry   = (d.country      || '').trim();\nconst hunterEnriched  = !!hunterCompany;\n\nreturn [{\n  json: {\n    ...lead,\n    // Prefer Hunter company name over domain-derived one if available\n    enriched_company     : hunterCompany || lead.enriched_company,\n    hunter_company       : hunterCompany,\n    hunter_industry      : hunterIndustry,\n    hunter_employee_count: hunterSize,\n    hunter_country       : hunterCountry,\n    hunter_enriched      : hunterEnriched\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "16c6c148-6589-4802-8f47-0a0a780154e2",
      "name": "Note \u2014 Stage ",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6784,
        1328
      ],
      "parameters": {
        "color": 3,
        "width": 340,
        "height": 150,
        "content": "## \ud83d\udeaa Stage 1 \u2014 Lead Entry\nPOST any lead JSON to the webhook URL.\n\n**Swap options:** HubSpot Trigger \u00b7 Pipedrive Trigger \u00b7 Typeform Trigger \u00b7 Google Sheets Trigger"
      },
      "typeVersion": 1
    },
    {
      "id": "f7dc647e-6988-427a-9b7c-d70febfd9b39",
      "name": "Note \u2014 Stage 7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6416,
        1312
      ],
      "parameters": {
        "color": 3,
        "width": 300,
        "height": 166,
        "content": "## \ud83d\udd27 Stage 2 \u2014 Normalize\nMaps any payload to a shared schema.\n\nAdd field aliases here if your source uses different field names (e.g. `full_name` instead of `first_name`)."
      },
      "typeVersion": 1
    },
    {
      "id": "6adc0f48-0f9c-43d2-aacb-c939dc7bfc39",
      "name": "Note \u2014 Stage 8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5488,
        1280
      ],
      "parameters": {
        "color": 3,
        "width": 300,
        "height": 198,
        "content": "## \ud83d\udd0d Stage 3 \u2014 Enrich (Free)\nDerives domain, seniority, and company from form data. Zero API keys needed.\n\n**Optional upgrade:** Replace with an HTTP Request to Hunter.io, Apollo.io, or Clearbit."
      },
      "typeVersion": 1
    },
    {
      "id": "1875fff0-ea0f-4234-b890-8d38a3b5bedd",
      "name": "Note \u2014 Stage 9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4608,
        1280
      ],
      "parameters": {
        "color": 5,
        "width": 360,
        "height": 198,
        "content": "## \ud83e\udd16 Stage 4 \u2014 AI Score\n\u26a0\ufe0f Select your OpenRouter credentials as instructed in step 2b\n\nChange model to any OpenRouter model:\n- `openai/gpt-4o-mini` (fast, cheap)\n- `anthropic/claude-haiku-3-5` (smart)\n- `meta-llama/llama-3.1-8b-instruct` (free tier)"
      },
      "typeVersion": 1
    },
    {
      "id": "7c05a1dc-c57c-42b8-a875-ca3eb7eb1175",
      "name": "Note \u2014 Stage 10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4080,
        1296
      ],
      "parameters": {
        "color": 3,
        "width": 280,
        "height": 150,
        "content": "## \ud83d\udd00 Stage 5 \u2014 Route by Tier\nOutput 0 \u2192 Hot (score \u226570)\nOutput 1 \u2192 Warm (score 40\u201369)\nOutput 2 \u2192 Cold (score <40)\n\nAdjust thresholds in the AI prompt (Stage 4 note)."
      },
      "typeVersion": 1
    },
    {
      "id": "0edbd1e3-9a71-405c-bc6e-c30f8cde5311",
      "name": "Note \u2014 Stage 11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2480,
        1408
      ],
      "parameters": {
        "color": 5,
        "width": 352,
        "height": 278,
        "content": "## \ud83d\udcca Stage 6 \u2014 Log to Sheets\n\u26a0\ufe0f Connect your Google account and set YOUR_SPREADSHEET_ID.\n\n**Swap options:** Airtable \u00b7 HubSpot \u00b7 Pipedrive \u00b7 HTTP Request to any CRM\n\nsample sheet structure:\nhttps://docs.google.com/spreadsheets/d/1_eB7pfTpiiQckejXbVsRPnAy2lAiH3CSxSKK5Suri34/edit?usp=sharing"
      },
      "typeVersion": 1
    },
    {
      "id": "53347d98-5610-4a8d-88b0-ee8cbc1fc609",
      "name": "Lead entry webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -6560,
        1504
      ],
      "parameters": {
        "path": "lead-qualifier",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "fc2dfc06-e887-42e5-b728-c95925f2d300",
      "name": "Normalize lead fields",
      "type": "n8n-nodes-base.set",
      "position": [
        -6320,
        1504
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a01",
              "name": "first_name",
              "type": "string",
              "value": "={{ ($json.first_name || ($json.body && $json.body.first_name) || (($json.name || ($json.body && $json.body.name) || '').split(' ')[0]) || '').trim() }}"
            },
            {
              "id": "a02",
              "name": "last_name",
              "type": "string",
              "value": "={{ ($json.last_name || ($json.body && $json.body.last_name) || (($json.name || ($json.body && $json.body.name) || '').split(' ').slice(1).join(' ') || '').trim()) }}"
            },
            {
              "id": "a03",
              "name": "email",
              "type": "string",
              "value": "={{ (($json.email || ($json.body && $json.body.email) || '')).toLowerCase().trim() }}"
            },
            {
              "id": "a04",
              "name": "company",
              "type": "string",
              "value": "={{ ($json.company || ($json.body && $json.body.company) || $json.organization || ($json.body && $json.body.organization) || '').trim() }}"
            },
            {
              "id": "a05",
              "name": "job_title",
              "type": "string",
              "value": "={{ ($json.job_title || ($json.body && $json.body.job_title) || $json.title || ($json.body && $json.body.title) || $json.role || ($json.body && $json.body.role) || '').trim() }}"
            },
            {
              "id": "a06",
              "name": "phone",
              "type": "string",
              "value": "={{ ($json.phone || ($json.body && $json.body.phone) || $json.phone_number || ($json.body && $json.body.phone_number) || '').trim() }}"
            },
            {
              "id": "a07",
              "name": "message",
              "type": "string",
              "value": "={{ ($json.message || ($json.body && $json.body.message) || $json.notes || ($json.body && $json.body.notes) || $json.comment || ($json.body && $json.body.comment) || '').trim() }}"
            },
            {
              "id": "a08",
              "name": "source",
              "type": "string",
              "value": "={{ $json.source || ($json.body && $json.body.source) || 'webhook' }}"
            },
            {
              "id": "a09",
              "name": "submitted_at",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8b357987-e4a7-4deb-ad8d-2dc5feda575f",
      "name": "Build AI prompt",
      "type": "n8n-nodes-base.set",
      "position": [
        -4640,
        1504
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "p01",
              "name": "system_prompt",
              "type": "string",
              "value": "You are a B2B lead qualification expert. Score this inbound lead using the BANT framework. Return ONLY a valid JSON object \u2014 no prose, no markdown fences, no code blocks.\n\nJSON shape:\n{\"score\": integer 0-100, \"tier\": \"hot|warm|cold\", \"budget\": integer 0-25, \"authority\": integer 0-25, \"need\": integer 0-25, \"timeline\": integer 0-25, \"reasoning\": \"one sentence max\", \"recommended_action\": \"one sentence max\"}\n\nScoring criteria:\n- Budget (0-25): Work email from a recognizable company = 18-25. Personal email (gmail/yahoo/hotmail/outlook/icloud) = 5-10. Unknown small domain = 10-15.\n- Authority (0-25): CEO/CTO/CXO/VP/Director/Head of/Founder/President/Owner = 20-25. Senior Manager/Lead/Principal/Architect = 12-18. Analyst/Coordinator/Associate = 6-12. Intern/Student/Assistant/Trainee = 0-5.\n- Need (0-25): Explicit pain point or active evaluation mentioned in message = 18-25. General interest or curiosity = 10-15. Empty or very vague message = 5.\n- Timeline (0-25): Urgent language (ASAP, this quarter, evaluating now, need by, urgent) = 20-25. Mild signals = 12-16. No timeline signals = 10.\n\nRules:\n- score MUST equal budget + authority + need + timeline exactly\n- score >= 70 \u2192 tier must be \"hot\"\n- 40 <= score < 70 \u2192 tier must be \"warm\"\n- score < 40 \u2192 tier must be \"cold\"\n- Return nothing except the JSON object"
            },
            {
              "id": "p02",
              "name": "user_message",
              "type": "string",
              "value": "={{ 'Name: ' + $json.first_name + ' ' + $json.last_name + '\\nEmail: ' + $json.email + '\\nCompany: ' + $json.enriched_company + '\\nIndustry: ' + ($json.hunter_industry || 'unknown') + '\\nEmployee count: ' + ($json.hunter_employee_count || 'unknown') + '\\nJob title: ' + $json.enriched_job_title + '\\nSeniority: ' + $json.seniority + '\\nWork email: ' + String($json.is_work_email) + '\\nMessage: ' + ($json.message || '(none)') + '\\nSource: ' + $json.source }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "1f4d178c-679f-46a7-80c9-413fce48bb30",
      "name": "AI score via OpenRouter",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -4400,
        1504
      ],
      "parameters": {
        "url": "https://openrouter.ai/api/v1/chat/completions",
        "body": "={{ JSON.stringify({ model: 'openai/gpt-4o-mini', temperature: 0, max_tokens: 400, messages: [{ role: 'system', content: $json.system_prompt }, { role: 'user', content: $json.user_message }] }) }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "rawContentType": "application/json",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "df7c8802-8951-4136-84a3-acfcde2a8396",
      "name": "Parse AI score",
      "type": "n8n-nodes-base.code",
      "position": [
        -4160,
        1504
      ],
      "parameters": {
        "jsCode": "const raw = items[0].json.choices?.[0]?.message?.content || '{}';\nconst cleaned = raw.replace(/```json|```/g, '').trim();\nlet parsed = {};\ntry {\n  parsed = JSON.parse(cleaned);\n} catch(e) {\n  parsed = {\n    score: 20, tier: 'cold',\n    budget: 5, authority: 5, need: 5, timeline: 5,\n    reasoning: 'AI response could not be parsed \u2014 review manually',\n    recommended_action: 'Check the Parse AI score node output for raw response'\n  };\n}\nreturn [{ json: { ...items[0].json, ...parsed } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "0d8fe46a-9399-4103-87a5-813411c0cf43",
      "name": "Route by lead tier",
      "type": "n8n-nodes-base.switch",
      "position": [
        -3936,
        1472
      ],
      "parameters": {
        "rules": {
          "rules": [
            {
              "value2": "hot"
            },
            {
              "output": 1,
              "value2": "warm"
            },
            {
              "output": 2,
              "value2": "cold"
            }
          ]
        },
        "value1": "={{ $json.tier }}",
        "dataType": "string",
        "fallbackOutput": 2
      },
      "typeVersion": 1
    },
    {
      "id": "3dff79f7-5d15-4463-b337-68603942bb90",
      "name": "Slack \u2014 hot lead alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        -3632,
        1008
      ],
      "parameters": {
        "text": "={{ '\ud83d\udd25 *Hot Lead!* Score: *' + $json.score + '/100*\\n\\n*' + $node['Enrich from email domain'].json.first_name + ' ' + $node['Enrich from email domain'].json.last_name + '* \u2014 ' + $node['Enrich from email domain'].json.enriched_job_title + ' @ *' + $node['Enrich from email domain'].json.enriched_company + '*\\n\ud83d\udce7 ' + $node['Enrich from email domain'].json.email + '\\n\ud83c\udfe2 ' + ($json.hunter_industry || '') + ($json.hunter_employee_count ? '  \u00b7  ' + $json.hunter_employee_count + ' employees' : '') + '\\n\ud83d\udcac _\"' + ($node['Enrich from email domain'].json.message || 'No message') + '\"_\\n\\n\ud83e\udde0 ' + $json.reasoning + '\\n\ud83d\udc49 ' + $json.recommended_action + '\\n\\nB: ' + $json.budget + '  \u00b7  A: ' + $json.authority + '  \u00b7  N: ' + $json.need + '  \u00b7  T: ' + $json.timeline }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "sales-alerts"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "5b661fb8-55f8-444a-8756-d34ea8fa1f7f",
      "name": "Book a call URL",
      "type": "n8n-nodes-base.set",
      "position": [
        -3424,
        1008
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"book_a_call_url\": \"YOUR_BOOK_A_CALL_URL\",\n  \"name\": \"YOUR_NAME_HERE\"\n}\n"
      },
      "typeVersion": 3.4
    },
    {
      "id": "36668fe3-9f68-482d-9522-f6f1cbe078df",
      "name": "Gmail \u2014 hot outreach",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -3200,
        1008
      ],
      "parameters": {
        "sendTo": "={{ $node['Enrich from email domain'].json.email }}",
        "message": "={{ 'Hi ' + $node['Enrich from email domain'].json.first_name + ',' + '\\n\\nI came across your inquiry and wanted to reach out personally. Based on what you shared, I think there is a strong fit.\\n\\nWould you be open to a quick 20-minute call this week? I can walk you through exactly how we can help ' + ($node['Enrich from email domain'].json.enriched_company || 'your team') + '.\\n\\n\ud83d\udc49 Book a time: ' + $json.book_a_call_url + '\\n\\nLooking forward to connecting.\\n\\nBest,\\n' + $json.name  }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ 'Quick question, ' + $node['Enrich from email domain'].json.first_name }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "47dceef1-4500-450d-a8a4-22290bc1d061",
      "name": "Hot Lead Logging",
      "type": "n8n-nodes-base.set",
      "position": [
        -2992,
        1008
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a4e79d37-6c28-4d22-b925-a2aef09ce87f",
              "name": "Full Name",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.first_name }} {{ $node['Enrich from email domain'].json.last_name || '' }}"
            },
            {
              "id": "21e6dee5-dfb7-42e2-81c0-2ce4a2286e08",
              "name": "Email",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.email }}"
            },
            {
              "id": "aa80814e-3082-4c83-a011-60ba0f53d38c",
              "name": "Phone",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.phone }}"
            },
            {
              "id": "2342e88b-a692-460b-8ca1-d98f87854903",
              "name": "Source",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.source }}"
            },
            {
              "id": "9171edb6-cda5-45f0-8256-bf503074766b",
              "name": "Company",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.company }}"
            },
            {
              "id": "582a7937-11e9-4d79-ac50-17c63c29060b",
              "name": "Job Title",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.job_title }}"
            },
            {
              "id": "f2b14b7d-7ad3-4c24-ae78-c7d8a5f6febc",
              "name": "Website",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.domain }}"
            },
            {
              "id": "8289503a-e576-4559-8f0e-b2b30015e672",
              "name": "Submitted At ",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.submitted_at }}"
            },
            {
              "id": "29e02c4b-a505-47c3-8989-ff31d3fdaf46",
              "name": "Sheet Name",
              "type": "string",
              "value": "Hot Leads"
            },
            {
              "id": "c7f34492-9af0-418d-9485-130469663b88",
              "name": "Reason",
              "type": "string",
              "value": "={{ $node['Parse AI score'].json.reasoning }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "7232c3c2-3732-4b66-9549-b66b28e6d20e",
      "name": "Warm Lead - Book a call",
      "type": "n8n-nodes-base.set",
      "position": [
        -3600,
        1488
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"links\": \"YOUR_BOOK_A_CALL_URL\",\n  \"name\": \"YOUR_NAME_HERE\"\n}\n"
      },
      "typeVersion": 3.4
    },
    {
      "id": "47548d14-39fd-4f7f-872a-ff422e99a1b9",
      "name": "Gmail \u2014 warm nurture",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -3328,
        1488
      ],
      "parameters": {
        "sendTo": "={{ $node['Enrich from email domain'].json.email }}",
        "message": "={{ 'Hi ' + $node['Enrich from email domain'].json.first_name + ',' + '\\n\\nYou can book a call here whenever it suits you:\\n\\n\ud83d\udc49 ' + $json.links + '\\n\\nHappy to connect whenever the timing feels right \u2014 no pressure at all.\\n\\nBest,\\n' + $json.name  }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ 'Something useful for ' + ($node['Enrich from email domain'].json.enriched_company || $json.first_name) }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "2734c6ad-3cdb-4583-85b8-4a052e20f5f5",
      "name": "Tag \u2014 cold lead",
      "type": "n8n-nodes-base.set",
      "position": [
        -3472,
        1952
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c01",
              "name": "crm_tag",
              "type": "string",
              "value": "={{ 'cold-' + new Date().toISOString().slice(0,7) }}"
            },
            {
              "id": "c02",
              "name": "nurture_list",
              "type": "string",
              "value": "newsletter"
            },
            {
              "id": "c03",
              "name": "follow_up_in_days",
              "type": "string",
              "value": "90"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "964b7bd0-7197-4802-8611-82fe80e1e530",
      "name": "Cold Lead Logging",
      "type": "n8n-nodes-base.set",
      "position": [
        -3168,
        1952
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a4e79d37-6c28-4d22-b925-a2aef09ce87f",
              "name": "Full Name",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.first_name }} {{ $node['Enrich from email domain'].json.last_name || '' }}"
            },
            {
              "id": "21e6dee5-dfb7-42e2-81c0-2ce4a2286e08",
              "name": "Email",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.email }}"
            },
            {
              "id": "aa80814e-3082-4c83-a011-60ba0f53d38c",
              "name": "Phone",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.phone }}"
            },
            {
              "id": "2342e88b-a692-460b-8ca1-d98f87854903",
              "name": "Source",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.source }}"
            },
            {
              "id": "9171edb6-cda5-45f0-8256-bf503074766b",
              "name": "Company",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.company }}"
            },
            {
              "id": "582a7937-11e9-4d79-ac50-17c63c29060b",
              "name": "Job Title",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.job_title }}"
            },
            {
              "id": "f2b14b7d-7ad3-4c24-ae78-c7d8a5f6febc",
              "name": "Website",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.domain }}"
            },
            {
              "id": "8289503a-e576-4559-8f0e-b2b30015e672",
              "name": "Submitted At ",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.submitted_at }}"
            },
            {
              "id": "29e02c4b-a505-47c3-8989-ff31d3fdaf46",
              "name": "Sheet Name",
              "type": "string",
              "value": "Cold Leads"
            },
            {
              "id": "bdf5446d-1b59-48f4-ac09-12d4de579c87",
              "name": "Reason",
              "type": "string",
              "value": "={{ $node['Parse AI score'].json.reasoning }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "26bcf164-1b66-422e-9aa1-8cb4eea56e66",
      "name": "Warm Lead Logging",
      "type": "n8n-nodes-base.set",
      "position": [
        -3024,
        1488
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a4e79d37-6c28-4d22-b925-a2aef09ce87f",
              "name": "Full Name",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.first_name }} {{ $node['Enrich from email domain'].json.last_name || '' }}"
            },
            {
              "id": "21e6dee5-dfb7-42e2-81c0-2ce4a2286e08",
              "name": "Email",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.email }}"
            },
            {
              "id": "aa80814e-3082-4c83-a011-60ba0f53d38c",
              "name": "Phone",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.phone }}"
            },
            {
              "id": "2342e88b-a692-460b-8ca1-d98f87854903",
              "name": "Source",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.source }}"
            },
            {
              "id": "9171edb6-cda5-45f0-8256-bf503074766b",
              "name": "Company",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.company }}"
            },
            {
              "id": "582a7937-11e9-4d79-ac50-17c63c29060b",
              "name": "Job Title",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.job_title }}"
            },
            {
              "id": "f2b14b7d-7ad3-4c24-ae78-c7d8a5f6febc",
              "name": "Website",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.domain }}"
            },
            {
              "id": "8289503a-e576-4559-8f0e-b2b30015e672",
              "name": "Submitted At ",
              "type": "string",
              "value": "={{ $node['Enrich from email domain'].json.submitted_at }}"
            },
            {
              "id": "29e02c4b-a505-47c3-8989-ff31d3fdaf46",
              "name": "Sheet Name",
              "type": "string",
              "value": "Warm Leads"
            },
            {
              "id": "cc5b873d-f103-4856-ac78-65093c9855c2",
              "name": "Reason",
              "type": "string",
              "value": "={{ $node['Parse AI score'].json.reasoning }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "48a93585-fa2e-4ca4-ab63-8a400973a43f",
      "name": "Google Sheets \u2014 log lead",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -2672,
        1488
      ],
      "parameters": {
        "columns": {
          "value": {
            "Email": "={{ $json.Email }}",
            "Phone": "={{ $json.Phone }}",
            "Reason": "={{ $json.Reason }}",
            "Source": "={{ $json.Source }}",
            "Company": "={{ $json.Company }}",
            "Website": "={{ $json.Website }}",
            "Full Name": "={{ $json['Full Name'] }}",
            "Job Title": "={{ $json['Job Title'] }}",
            "Submitted At ": "={{ $json['Submitted At '] }}"
          },
          "schema": [
            {
              "id": "Full Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Full Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Company",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Company",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Job Title",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Job Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Submitted At ",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Submitted At ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Reason",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Reason",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json['Sheet Name'] }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "7ff18804-7a7d-4194-9f7d-758c097ae263",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -7456,
        1264
      ],
      "parameters": {
        "width": 608,
        "height": 592,
        "content": "## \ud83c\udfaf AI-Powered B2B Lead Qualifier\n\n### Who is this for?\nSales teams, solo founders, and RevOps professionals who receive inbound leads from web forms, CRMs, HubSpot, Typeform, Pipedrive, or any other source \u2014 and want to automatically qualify, prioritize, and respond to leads without manual work.\n\n---\n\n## \u2699\ufe0f What This Workflow Does\n\nThis workflow automatically captures inbound leads, enriches them with company intelligence, scores them using the BANT framework via GPT-4o-mini, and routes them into hot, warm, or cold pipelines.\n\n- \ud83d\udd25 **Hot Leads** \u2192 Slack alert + personalized outreach email  \n- \ud83c\udf24\ufe0f **Warm Leads** \u2192 Automated nurture email  \n- \u2744\ufe0f **Cold Leads** \u2192 CRM tagging + 90-day follow-up flag  \n\nAll leads are automatically logged into Google Sheets.\n\n---\n\n## \u26a0\ufe0f Setup Before Running\n\n- Add your OpenRouter API key to `Header Auth OpenRouter`\n- Replace Hunter.io `api_key` with your own key (optional)\n- Connect Gmail OAuth2\n- Connect Slack and ensure `#sales-alerts` exists\n- Replace spreadsheet ID with:\n  `YOUR_SPREADSHEET_ID_HERE`\n- Replace booking URL with:\n  `YOUR_BOOK_A_CALL_URL`"
      },
      "typeVersion": 1
    },
    {
      "id": "dbe31b55-5897-416d-a0ff-f94cdce33de7",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3744,
        576
      ],
      "parameters": {
        "color": 7,
        "width": 976,
        "height": 576,
        "content": "## \ud83d\udd25 Hot Lead Flow \u2014 Setup (Quick)\n\n### Slack\n- Connect Slack OAuth in n8n\n- Ensure channel exists: `#sales-alerts`\n- Node sends instant hot lead alert there\n\n---\n\n### Gmail\n- Connect Gmail via OAuth2 in n8n\n- Used to send automated outreach emails to hot leads\n- Uses lead data + AI message template\n\n---\n\n### Book a Call Link\nReplace:\n`YOUR_BOOK_A_CALL_URL`\n\nExample:\n`https://cal.com/your-name`\n\n\ud83d\udc49 Replace YOUR_NAME_HERE with your name \u2014 it will be used in the Complimentary Close of the email body.\n\nUsed inside Gmail email for scheduling calls\n\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "ee28b476-835b-41dd-b991-e2f1c0171b71",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3664,
        1232
      ],
      "parameters": {
        "color": 7,
        "width": 784,
        "height": 400,
        "content": "## \ud83c\udf24\ufe0f Warm Lead Flow \u2014 Setup (Quick)\n\n### Book a Call Node\n- Replace `YOUR_BOOK_A_CALL_URL` with your actual scheduling link  \n- \ud83d\udc49 Replace YOUR_NAME_HERE with your name \u2014 it will be used in the Complimentary Close of the email body.\n- This link is reused inside warm nurture emails  \n\n---\n\n### Gmail\n- Connect Gmail via OAuth2 in n8n  \n- Sends soft nurture email (no hard selling)  \n- Uses warm lead context + booking link from previous node  "
      },
      "typeVersion": 1
    },
    {
      "id": "d108fda8-0c2b-4497-bd0e-afda8b01d578",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3552,
        1792
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 304,
        "content": "## \u2744\ufe0f Cold Lead Flow \u2014 Setup (Quick)\n\n### CRM / Tagging Node\n- This node just marks lead as **Cold**\n- No external setup needed\n- Ensure field/value is consistent (e.g. `Cold Leads` tag)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "ab354396-0908-4bc3-8476-6c4766b805a0",
      "name": "Enrich from email domain",
      "type": "n8n-nodes-base.code",
      "position": [
        -5360,
        1504
      ],
      "parameters": {
        "jsCode": "const item = items[0].json;\nconst email = (item.email || '').toLowerCase();\nconst domain = email.includes('@') ? email.split('@')[1] : '';\nconst domainBase = domain.split('.')[0];\nconst companyFromDomain = domainBase.charAt(0).toUpperCase() + domainBase.slice(1);\n\nconst personalProviders = ['gmail','yahoo','hotmail','outlook','protonmail','icloud','aol','live','msn','me','zoho'];\nconst isPersonalEmail = personalProviders.some(p => domain.includes(p));\nconst isWorkEmail = !isPersonalEmail && domain !== '';\n\nconst title = (item.job_title || '').toLowerCase();\nconst seniorKw = ['ceo','cto','coo','cfo','cpo','chief','founder','co-founder','president','vp','vice president','director','head of','owner','partner','managing'];\nconst juniorKw = ['intern','student','trainee','junior','assistant','associate','coordinator','entry level'];\nconst midKw = ['manager','lead','senior','principal','architect','specialist','supervisor'];\n\nlet seniority = 'mid';\nif (seniorKw.some(k => title.includes(k))) seniority = 'senior';\nelse if (juniorKw.some(k => title.includes(k))) seniority = 'junior';\nelse if (midKw.some(k => title.includes(k))) seniority = 'mid';\n\nreturn [{\n  json: {\n    ...item,\n    domain,\n    enriched_company: item.company || companyFromDomain || '',\n    enriched_job_title: item.job_title || '',\n    seniority,\n    is_personal_email: isPersonalEmail,\n    is_work_email: isWorkEmail,\n    company_domain: domain\n  }\n}];"
      },
      "typeVersion": 2
    }
  ],
  "connections": {
    "Parse AI score": {
      "main": [
        [
          {
            "node": "Route by lead tier",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Book a call URL": {
      "main": [
        [
          {
            "node": "Gmail \u2014 hot outreach",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build AI prompt": {
      "main": [
        [
          {
            "node": "AI score via OpenRouter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hot Lead Logging": {
      "main": [
        [
          {
            "node": "Google Sheets \u2014 log lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI extract fields": {
      "main": [
        [
          {
            "node": "Parse extracted fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cold Lead Logging": {
      "main": [
        [
          {
            "node": "Google Sheets \u2014 log lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tag \u2014 cold lead": {
      "main": [
        [
          {
            "node": "Cold Lead Logging",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Warm Lead Logging": {
      "main": [
        [
          {
            "node": "Google Sheets \u2014 log lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lead entry webhook": {
      "main": [
        [
          {
            "node": "Normalize lead fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by lead tier": {
      "main": [
        [
          {
            "node": "Slack \u2014 hot lead alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Warm Lead - Book a call",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Tag \u2014 cold lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize lead fields": {
      "main": [
        [
          {
            "node": "Build extraction prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Hunter response": {
      "main": [
        [
          {
            "node": "Build AI prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail \u2014 hot outreach": {
      "main": [
        [
          {
            "node": "Hot Lead Logging",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail \u2014 warm nurture": {
      "main": [
        [
          {
            "node": "Warm Lead Logging",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse extracted fields": {
      "main": [
        [
          {
            "node": "Enrich from email domain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI score via OpenRouter": {
      "main": [
        [
          {
            "node": "Parse AI score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build extraction prompt": {
      "main": [
        [
          {
            "node": "AI extract fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hunter.io domain search": {
      "main": [
        [
          {
            "node": "Parse Hunter response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Warm Lead - Book a call": {
      "main": [
        [
          {
            "node": "Gmail \u2014 warm nurture",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enrich from email domain": {
      "main": [
        [
          {
            "node": "Hunter.io domain search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack \u2014 hot lead alert": {
      "main": [
        [
          {
            "node": "Book a call URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}