{
  "name": "SoloFlows \u2014 Agency Lead Capture & Qualify",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "soloflows-lead",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "a1b2c3d4-0001-4000-8000-000000000001",
      "name": "Inbound Lead (Webhook)",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        320
      ],
      "webhookId": "soloflows-lead-capture"
    },
    {
      "parameters": {
        "jsCode": "// Normalize + score the inbound lead.\n// Expects JSON body: { name, email, company, budget, message }\nconst body = $input.first().json.body || $input.first().json;\n\nconst email = (body.email || '').trim().toLowerCase();\nconst name = (body.name || '').trim();\nconst company = (body.company || '').trim();\nconst message = (body.message || '').trim();\n\n// Parse a rough budget number from free text or a number.\nlet budgetNum = 0;\nif (typeof body.budget === 'number') {\n  budgetNum = body.budget;\n} else if (typeof body.budget === 'string') {\n  budgetNum = parseInt(body.budget.replace(/[^0-9]/g, ''), 10) || 0;\n}\n\n// Simple qualification score (0-100), collecting a human-readable reason for\n// each rule that fires so the alert can explain itself.\nlet score = 0;\nconst reasons = [];\nif (email.includes('@') && !email.endsWith('@gmail.com') && !email.endsWith('@yahoo.com')) { score += 30; reasons.push('business email'); }\nif (company.length > 1) { score += 20; reasons.push('has company'); }\nif (budgetNum >= 1000) { score += 30; reasons.push('budget >= $1k'); }\nelse if (budgetNum >= 250) { score += 15; reasons.push('budget >= $250'); }\nif (message.length > 40) { score += 20; reasons.push('detailed message'); }\nif (score > 100) score = 100;\n\nconst tier = score >= 70 ? 'hot' : score >= 40 ? 'warm' : 'cold';\n// qualified_reason lists which rules fired, so the Slack alert is self-explanatory.\nconst qualified_reason = reasons.length ? reasons.join(' + ') : 'no criteria met';\n\nreturn [{\n  json: {\n    name,\n    email,\n    company,\n    budget: budgetNum,\n    message,\n    score,\n    tier,\n    qualified_reason,\n    capturedAt: new Date().toISOString(),\n  }\n}];"
      },
      "id": "a1b2c3d4-0002-4000-8000-000000000002",
      "name": "Normalize & Score",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        320
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Leads",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Captured At": "={{ $json.capturedAt }}",
            "Name": "={{ $json.name }}",
            "Email": "={{ $json.email }}",
            "Company": "={{ $json.company }}",
            "Budget": "={{ $json.budget }}",
            "Score": "={{ $json.score }}",
            "Tier": "={{ $json.tier }}",
            "Message": "={{ $json.message }}"
          }
        },
        "options": {}
      },
      "id": "a1b2c3d4-0003-4000-8000-000000000003",
      "name": "Log to CRM (Google Sheet)",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        720,
        320
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "REPLACE_WITH_YOUR_CREDENTIAL_ID",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "cond-hot",
              "leftValue": "={{ $json.score }}",
              "rightValue": 70,
              "operator": {
                "type": "number",
                "operation": "gte"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "a1b2c3d4-0004-4000-8000-000000000004",
      "name": "Hot Lead?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        960,
        320
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "YOUR_SLACK_CHANNEL_ID",
          "mode": "id"
        },
        "text": "=:fire: *{{ $json.tier === \"hot\" ? \"Hot\" : $json.tier === \"warm\" ? \"Warm\" : \"Cold\" }} lead* ({{ $json.score }}/100)\n*{{ $json.name }}* \u2014 {{ $json.company }}\n{{ $json.email }} \u00b7 budget ~${{ $json.budget }}\n_Why:_ {{ $json.qualified_reason }}\n> {{ $json.message }}",
        "otherOptions": {}
      },
      "id": "a1b2c3d4-0005-4000-8000-000000000005",
      "name": "Alert in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        1200,
        220
      ],
      "webhookId": "soloflows-slack",
      "credentials": {
        "slackApi": {
          "id": "REPLACE_WITH_YOUR_CREDENTIAL_ID",
          "name": "Slack account"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ { \"ok\": true, \"score\": $json.score, \"tier\": $json.tier } }}",
        "options": {}
      },
      "id": "a1b2c3d4-0006-4000-8000-000000000006",
      "name": "Respond OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1200,
        420
      ]
    },
    {
      "parameters": {
        "content": "## SoloFlows \u2014 Agency Lead Capture & Qualify\n\n**What it does:** Catches an inbound lead via webhook, normalizes + scores it, logs it to a Google Sheet CRM, and Slack-pings you for hot leads.\n\n**Setup (5 min):**\n1. Open the **Inbound Lead** node \u2192 copy the production webhook URL \u2192 point your contact form / Typeform / Tally at it (POST JSON: `name, email, company, budget, message`).\n2. Connect your **Google Sheets** credential, set the Sheet ID + a tab named `Leads` with matching headers.\n3. Connect your **Slack** credential + pick a channel.\n4. Tweak the scoring rules in the **Normalize & Score** node to fit your niche.\n\n**Tested on:** n8n v1.58+ (Cloud & self-hosted).\n\nFree sample by SoloFlows.",
        "height": 300,
        "width": 420
      },
      "id": "a1b2c3d4-0007-4000-8000-000000000007",
      "name": "README",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        200,
        -40
      ]
    }
  ],
  "connections": {
    "Inbound Lead (Webhook)": {
      "main": [
        [
          {
            "node": "Normalize & Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize & Score": {
      "main": [
        [
          {
            "node": "Log to CRM (Google Sheet)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to CRM (Google Sheet)": {
      "main": [
        [
          {
            "node": "Hot Lead?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hot Lead?": {
      "main": [
        [
          {
            "node": "Alert in Slack",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert in Slack": {
      "main": [
        [
          {
            "node": "Respond OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "soloflows-sample-v1",
  "meta": {
    "templateCredsSetupCompleted": false,
    "source": "SoloFlows \u2014 free sample workflow"
  },
  "tags": [
    {
      "name": "SoloFlows"
    },
    {
      "name": "lead-capture"
    }
  ]
}
