{
  "name": "Qualify leads from Google Sheets with AI and send them to Slack",
  "nodes": [
    {
      "id": "sticky-10",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -660,
        -80
      ],
      "parameters": {
        "color": 1,
        "width": 540,
        "height": 980,
        "content": "## Qualify leads from Google Sheets with AI and send them to Slack\n\n### Who's it for\nAnyone collecting leads from places that cannot be automated - Facebook groups,\nLinkedIn, WhatsApp, in-person referrals, or forums with a closed API. You do the\ncollecting, this does the qualifying.\n\n### How it works\nYou paste a post, message, or enquiry into a Google Sheet. Each new row triggers\nthe workflow, which sends the text to a language model together with a\ndescription of your business. The model returns a buying-intent score from 0 to\n10, a category, and a one-line reason. All three are written straight back to\nthe same row, so the sheet doubles as a lead tracker with full history. Only\nrows at or above your score threshold raise a Slack alert, which keeps the\nchannel signal-only.\n\n### How to set up\n1. Create a sheet with these headers: post_text, link, source, relevant, score,\n   category, reason, status.\n2. Select that sheet in both Google Sheets nodes.\n3. Describe your business in \"Configure here\" and set minScore.\n4. Add language model and Slack credentials.\n\n### Requirements\nA Google account, an OpenAI (or compatible) API key, and Slack.\n\n### How to customize\nReplace the Sheets trigger with a webhook or form submission. Adjust the scoring\nbands in the prompt, or add categories that match your services."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-11",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -300
      ],
      "parameters": {
        "color": 7,
        "width": 460,
        "height": 200,
        "content": "### 1. New row and configuration\nDescribe your business in the Set node - the model uses it to score."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-12",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        420,
        -300
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 200,
        "content": "### 2. AI qualification\nReturns score, category, and a one-line reason."
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-13",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        -300
      ],
      "parameters": {
        "color": 7,
        "width": 540,
        "height": 200,
        "content": "### 3. Write back and alert\nEvery row is scored. Only strong ones reach Slack."
      },
      "typeVersion": 1
    },
    {
      "id": "sheettrigger",
      "name": "New row in Google Sheets",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "event": "rowAdded",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": ""
        }
      },
      "typeVersion": 1
    },
    {
      "id": "config",
      "name": "Configure here",
      "type": "n8n-nodes-base.set",
      "position": [
        220,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f0",
              "name": "businessContext",
              "type": "string",
              "value": "We build and automate marketing websites (Webflow and WordPress) for small B2B and SaaS companies. Not e-commerce, not complex custom applications."
            },
            {
              "id": "f1",
              "name": "minScore",
              "type": "number",
              "value": "7"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "guard",
      "name": "Skip empty rows",
      "type": "n8n-nodes-base.filter",
      "position": [
        440,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "hastext",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.post_text }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "llm",
      "name": "Qualify the lead",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        660,
        0
      ],
      "parameters": {
        "text": "=You qualify inbound leads for this business:\n{{ $json.businessContext }}\n\nPost:\n\"\"\"\n{{ $json.post_text }}\n\"\"\"\nSource: {{ $json.source }}\n\nScore buying intent from 0 to 10:\n- 9 to 10: explicitly looking to hire someone now\n- 6 to 8: has a real project or problem and is weighing options\n- 3 to 5: general research, no project yet\n- 0 to 2: irrelevant, self-promotion, or a competitor selling\n\nCategorise as one of: new_website, redesign, platform_help, automation, seo, other.\n\nSet relevant to true only if this is a real person with a real need the business above could serve. Give one short sentence of reasoning, no hedging.",
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.5
    },
    {
      "id": "model",
      "name": "Language model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        620,
        220
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "parser",
      "name": "Structured output",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        760,
        220
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"relevant\": true,\n  \"score\": 8,\n  \"category\": \"new_website\",\n  \"reason\": \"Pre-launch founder with copy ready, asking who to hire.\"\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "writeback",
      "name": "Write score back to the row",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        900,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "score": "={{ $json.output.score }}",
            "reason": "={{ $json.output.reason }}",
            "status": "qualified",
            "category": "={{ $json.output.category }}",
            "relevant": "={{ $json.output.relevant }}",
            "row_number": "={{ $('New row in Google Sheets').item.json.row_number }}"
          },
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": ""
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "worth",
      "name": "Above the score threshold",
      "type": "n8n-nodes-base.if",
      "position": [
        1120,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "rel",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $('Qualify the lead').item.json.output.relevant }}",
              "rightValue": "true"
            },
            {
              "id": "score",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $('Qualify the lead').item.json.output.score }}",
              "rightValue": "={{ $('Configure here').first().json.minScore }}"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "slack",
      "name": "Alert the team in Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1340,
        0
      ],
      "parameters": {
        "text": "=*New lead - score {{ $('Qualify the lead').item.json.output.score }}/10* ({{ $('Qualify the lead').item.json.output.category }})\n_{{ $('Qualify the lead').item.json.output.reason }}_\n\n{{ $('New row in Google Sheets').item.json.post_text.slice(0, 500) }}\n\n<{{ $('New row in Google Sheets').item.json.link }}|Open the original>",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": ""
        },
        "otherOptions": {
          "mrkdwn": true
        }
      },
      "typeVersion": 2.3
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Configure here": {
      "main": [
        [
          {
            "node": "Skip empty rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Language model": {
      "ai_languageModel": [
        [
          {
            "node": "Qualify the lead",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Skip empty rows": {
      "main": [
        [
          {
            "node": "Qualify the lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Qualify the lead": {
      "main": [
        [
          {
            "node": "Write score back to the row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured output": {
      "ai_outputParser": [
        [
          {
            "node": "Qualify the lead",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "New row in Google Sheets": {
      "main": [
        [
          {
            "node": "Configure here",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Above the score threshold": {
      "main": [
        [
          {
            "node": "Alert the team in Slack",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Write score back to the row": {
      "main": [
        [
          {
            "node": "Above the score threshold",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}