{
  "name": "AI Lead Qualification -> HubSpot & Slack",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "lead-qualification",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "lead-webhook",
      "name": "Webhook - Inbound Lead",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [200, 300],
      "webhookId": "lead-qualification-hook"
    },
    {
      "parameters": {
        "resource": "chat",
        "operation": "complete",
        "model": "gpt-4o-mini",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a B2B SaaS lead qualification engine. Analyze the lead intake submission and return a strictly valid JSON object matching this schema:\n{\n  \"tier\": \"hot\" | \"warm\" | \"cold\",\n  \"score\": number (0-100),\n  \"rationale\": string (max 2 sentences),\n  \"budget_bracket\": \"<5k\" | \"5k-25k\" | \"25k+\",\n  \"fit_summary\": string\n}\n\nQualification criteria:\n- Hot: Budget > $5k, decision maker timeline < 30 days, clear pain point matching our product.\n- Warm: Budget defined, timeline 1-3 months, evaluating solutions.\n- Cold: Student, researcher, no budget, or vague scope.\nDo not return any markdown wrapping or text outside JSON."
            },
            {
              "role": "user",
              "content": "=Company: {{$json.body?.company || $json.company}}\nContact: {{$json.body?.name || $json.name}} ({{$json.body?.email || $json.email}})\nTeam Size: {{$json.body?.team_size || $json.team_size}}\nBudget: {{$json.body?.budget || $json.budget}}\nProject Description: {{$json.body?.description || $json.description}}\nTimeline: {{$json.body?.timeline || $json.timeline}}"
            }
          ]
        },
        "options": {
          "responseFormat": "json_object"
        }
      },
      "id": "lead-llm-score",
      "name": "OpenAI - Qualify & Score Lead",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1.4,
      "position": [440, 300],
      "credentials": {
        "openAiApi": {
          "id": "openai-cred-placeholder",
          "name": "OpenAI API Account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const incoming = $('Webhook - Inbound Lead').first().json.body || $('Webhook - Inbound Lead').first().json;\nconst aiRaw = $input.first().json.message?.content || $input.first().json;\n\nlet parsed = null;\ntry {\n  parsed = typeof aiRaw === 'string' ? JSON.parse(aiRaw) : aiRaw;\n} catch (err) {\n  parsed = null;\n}\n\nconst isValid = Boolean(\n  parsed &&\n  ['hot', 'warm', 'cold'].includes(parsed.tier) &&\n  typeof parsed.score === 'number' &&\n  typeof parsed.rationale === 'string'\n);\n\nif (!isValid) {\n  return [{\n    json: {\n      isValid: false,\n      lead_tag: 'needs_review',\n      tier: 'unclassified',\n      score: 0,\n      rationale: 'LLM output failed JSON contract schema validation.',\n      contact_email: incoming.email || 'unknown@domain.com',\n      contact_name: incoming.name || 'Unknown',\n      company: incoming.company || 'Unknown'\n    }\n  }];\n}\n\nreturn [{\n  json: {\n    isValid: true,\n    lead_tag: parsed.tier === 'hot' ? 'priority_sales' : 'nurture',\n    tier: parsed.tier,\n    score: parsed.score,\n    rationale: parsed.rationale,\n    budget_bracket: parsed.budget_bracket,\n    fit_summary: parsed.fit_summary,\n    contact_email: incoming.email,\n    contact_name: incoming.name,\n    company: incoming.company\n  }\n}];"
      },
      "id": "lead-schema-validate",
      "name": "Validate Schema & Classify",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [680, 300]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "cond-is-valid-schema",
              "leftValue": "={{ $json.isValid }}",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "rightValue": ""
            }
          ],
          "combinator": "and"
        }
      },
      "id": "lead-if-valid",
      "name": "Is Schema Valid?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [920, 300]
    },
    {
      "parameters": {
        "resource": "contact",
        "operation": "upsert",
        "email": "={{ $json.contact_email }}",
        "additionalFields": {
          "firstName": "={{ $json.contact_name.split(' ')[0] }}",
          "lastName": "={{ $json.contact_name.split(' ').slice(1).join(' ') }}",
          "company": "={{ $json.company }}",
          "leadStatus": "NEEDS_REVIEW",
          "notes": "={{ $json.rationale }}"
        }
      },
      "id": "lead-hubspot-flag",
      "name": "HubSpot - Flag Needs Review",
      "type": "n8n-nodes-base.hubspot",
      "typeVersion": 1,
      "position": [1160, 480],
      "credentials": {
        "hubspotOAuth2Api": {
          "id": "hubspot-cred-placeholder",
          "name": "HubSpot OAuth Account"
        }
      }
    },
    {
      "parameters": {
        "resource": "contact",
        "operation": "upsert",
        "email": "={{ $json.contact_email }}",
        "additionalFields": {
          "firstName": "={{ $json.contact_name.split(' ')[0] }}",
          "lastName": "={{ $json.contact_name.split(' ').slice(1).join(' ') }}",
          "company": "={{ $json.company }}",
          "leadStatus": "={{ $json.tier === 'hot' ? 'OPEN' : 'IN_PROGRESS' }}",
          "notes": "=[AI Score: {{ $json.score }}/100 - {{ $json.tier }}] {{ $json.rationale }} | Budget: {{ $json.budget_bracket }}"
        }
      },
      "id": "lead-hubspot-upsert",
      "name": "HubSpot - Upsert Contact",
      "type": "n8n-nodes-base.hubspot",
      "typeVersion": 1,
      "position": [1160, 200],
      "credentials": {
        "hubspotOAuth2Api": {
          "id": "hubspot-cred-placeholder",
          "name": "HubSpot OAuth Account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "cond-is-hot",
              "leftValue": "={{ $('Validate Schema & Classify').item.json.tier }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "rightValue": "hot"
            }
          ],
          "combinator": "and"
        }
      },
      "id": "lead-if-hot",
      "name": "Is Hot Lead?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1400, 200]
    },
    {
      "parameters": {
        "channel": "#leads-hot-alerts",
        "text": "=🔥 *Hot Lead Inbound*: {{ $('Validate Schema & Classify').item.json.contact_name }} from {{ $('Validate Schema & Classify').item.json.company }}\n*Score*: {{ $('Validate Schema & Classify').item.json.score }}/100\n*Budget*: {{ $('Validate Schema & Classify').item.json.budget_bracket }}\n*Why*: {{ $('Validate Schema & Classify').item.json.rationale }}",
        "options": {}
      },
      "id": "lead-slack-alert",
      "name": "Slack - Alert Sales Team",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [1640, 100],
      "credentials": {
        "slackApi": {
          "id": "slack-cred-placeholder",
          "name": "Slack Bot Account"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ { received: true, status: 'processed', qualified: $('Validate Schema & Classify').item.json.isValid, tier: $('Validate Schema & Classify').item.json.tier } }}",
        "options": {}
      },
      "id": "lead-respond",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [1880, 280]
    }
  ],
  "connections": {
    "Webhook - Inbound Lead": {
      "main": [
        [
          {
            "node": "OpenAI - Qualify & Score Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Qualify & Score Lead": {
      "main": [
        [
          {
            "node": "Validate Schema & Classify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Schema & Classify": {
      "main": [
        [
          {
            "node": "Is Schema Valid?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Schema Valid?": {
      "main": [
        [
          {
            "node": "HubSpot - Upsert Contact",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HubSpot - Flag Needs Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HubSpot - Flag Needs Review": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HubSpot - Upsert Contact": {
      "main": [
        [
          {
            "node": "Is Hot Lead?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Hot Lead?": {
      "main": [
        [
          {
            "node": "Slack - Alert Sales Team",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack - Alert Sales Team": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
