{
  "id": "VmSz7KyMN1yoISjA",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Convert inbound lead data from Webhook to AI-qualified Asana tasks",
  "tags": [],
  "nodes": [
    {
      "id": "5aedd31f-d30f-4b57-b0aa-97ae6dca00aa",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1472,
        0
      ],
      "parameters": {
        "width": 389,
        "height": 608,
        "content": "## \ud83c\udfaf AI-Powered Lead Enrichment & Qualification\n\n### How it works\nThis workflow automates lead enrichment and qualification using RocketReach and OpenAI. When a lead is submitted via webhook, it enriches the data with professional contact details, validates data quality, scores the lead using AI based on seniority and fit, and automatically creates tasks in Asana for high-quality leads while notifying your team via Slack.\n\n### Setup steps\n1. **Connect credentials**: RocketReach API, OpenAI API, Asana OAuth2, and Slack API\n2. **Configure webhook**: Copy the webhook URL from the trigger node and integrate it into your lead capture system\n3. **Customize scoring logic**: Adjust the AI prompt in \"AI Lead Scoring\" to match your ideal customer profile\n4. **Set thresholds**: Modify confidence (0.6) and score (6) filters based on your quality standards\n5. **Test**: Send a sample lead with `first_name`, `last_name`, `company`, `job_title`, `company_domain`, and `linkedin_url`"
      },
      "typeVersion": 1
    },
    {
      "id": "d768643d-7a9b-4ece-8aaa-6f095b41527e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1472,
        624
      ],
      "parameters": {
        "color": 2,
        "width": 448,
        "height": 323,
        "content": "## \ud83d\udce5 Data Ingestion & Normalization\nReceives lead data via webhook and structures it into a clean format for enrichment. Extracts key fields like name, company, job title, and LinkedIn URL."
      },
      "typeVersion": 1
    },
    {
      "id": "d1215b48-7b4c-4de6-99bf-4fb5c57edcba",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1008,
        624
      ],
      "parameters": {
        "color": 2,
        "width": 649,
        "height": 323,
        "content": "## \ud83d\udd0d Lead Enrichment & Quality Check\nEnriches leads with RocketReach to find professional emails and phone numbers. Calculates confidence scores based on email grade (A-D) and filters out low-quality data before AI scoring."
      },
      "typeVersion": 1
    },
    {
      "id": "f2181260-b5d5-4b5d-993f-86b40931221e",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        544
      ],
      "parameters": {
        "color": 2,
        "width": 521,
        "height": 483,
        "content": "## \ud83e\udd16 AI Lead Scoring & Filtering\nUses GPT-4o-mini to intelligently score leads (1-10) based on job seniority, company size, and data quality. Assigns priority levels and filters leads below threshold (score < 6)."
      },
      "typeVersion": 1
    },
    {
      "id": "9661b38a-aaab-47d7-ad52-526178f5abb0",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        224,
        480
      ],
      "parameters": {
        "color": 2,
        "width": 921,
        "height": 446,
        "content": "## \u2705 Task Creation & Notifications\nCreates Asana tasks for qualified leads and sends Slack notifications to your sales team. Disqualified leads also trigger notifications for tracking purposes."
      },
      "typeVersion": 1
    },
    {
      "id": "0d169a95-5dc0-4ec0-84b9-50270dc330d4",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1168,
        688
      ],
      "parameters": {
        "color": 3,
        "width": 380.3665987780041,
        "height": 233.59233786022102,
        "content": "## \ud83d\udd10 Credentials & Security\n**Required credentials**: RocketReach API key, OpenAI API key, Asana OAuth2, Slack API token.\n\n\u26a0\ufe0f **Important**: Replace the hardcoded RocketReach API key in the HTTP node with a credential. Never expose API keys in shared workflows."
      },
      "typeVersion": 1
    },
    {
      "id": "a240e684-7722-4619-a6bd-376b6e16625c",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1408,
        768
      ],
      "parameters": {
        "path": "lead-enrichment",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "a7a74541-9295-48a7-9e71-83e06b4f1d94",
      "name": "Normalize Lead Data",
      "type": "n8n-nodes-base.set",
      "position": [
        -1184,
        768
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "field1",
              "name": "firstName",
              "type": "string",
              "value": "={{ $json.body.first_name }}"
            },
            {
              "id": "field2",
              "name": "lastName",
              "type": "string",
              "value": "={{ $json.body.last_name }}"
            },
            {
              "id": "field3",
              "name": "company",
              "type": "string",
              "value": "={{ $json.body.company }}"
            },
            {
              "id": "field4",
              "name": "jobTitle",
              "type": "string",
              "value": "={{ $json.body.job_title }}"
            },
            {
              "id": "field5",
              "name": "domain",
              "type": "string",
              "value": "={{ $json.body.company_domain }}"
            },
            {
              "id": "field6",
              "name": "linkedinUrl",
              "type": "string",
              "value": "={{ $json.body.linkedin_url }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3a7da26c-c476-4dc0-8295-b70e9c0cca50",
      "name": "Quality Filter",
      "type": "n8n-nodes-base.if",
      "position": [
        -512,
        768
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "confidence-check",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.confidence ?? 0 }}",
              "rightValue": 0.6
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "2deca84b-f4dc-4c3f-bd08-f147b2763955",
      "name": "AI Lead Scoring",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -288,
        672
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "GPT-4O-MINI"
        },
        "options": {
          "temperature": 0.3
        },
        "messages": {
          "values": [
            {
              "content": "=You are a lead scoring AI. Score this lead from 1-10 based on job title seniority, company size, location, and data confidence.\n\nLead Data:\n- Name: {{ $json.name }}\n- Job Title: {{ $json.current_title }}\n- Company: {{ $json.current_employer }}\n- Email: {{ $json.emails?.[0]?.email ?? 'N/A' }}\n- Phone: {{ $json.phones?.[0]?.number ?? 'N/A' }}\n- Confidence: {{ $json.confidence }}\n- Location:{{ $json.location || 'unknown' }} \n-current Employer Id:{{ $json.current_employer_id }}\n- Company Size: {{ $json.current_employer_size ?? 'Unknown' }}\n\nReturn ONLY valid JSON with this exact structure (no markdown, no extra text):\n{\n  \"score\": <number 1-10>,\n  \"priority\": \"<High|Medium|Low>\",\n  \"reason\": \"<brief explanation>\"\n}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "0d26ce75-2ba9-4a07-b82e-454ac36d0ae4",
      "name": "Score Filter",
      "type": "n8n-nodes-base.if",
      "position": [
        288,
        672
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "score-check",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.score }}",
              "rightValue": 6
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "72d70e51-d767-405c-ab11-522e20826634",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        512,
        576
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"success\": true, \"message\": \"Lead processed successfully\", \"score\": $json.score, \"priority\": $json.priority, \"taskCreated\": true } }}"
      },
      "typeVersion": 1
    },
    {
      "id": "e98fe2c0-d12a-429e-9df5-a3368d441ed0",
      "name": "Respond - Low Confidence",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -224,
        864
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"success\": false, \"message\": \"Lead did not meet quality threshold\", \"reason\": \"Confidence score below 0.6\" } }}"
      },
      "typeVersion": 1
    },
    {
      "id": "a170efe0-cd46-4b97-961a-09893ee25445",
      "name": "Respond - Low Score",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        512,
        768
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"success\": false, \"message\": \"Lead did not qualify\", \"reason\": \"AI score below threshold\", \"score\": $json.aiScore } }}"
      },
      "typeVersion": 1
    },
    {
      "id": "0ad7e252-054e-403b-aa13-87960ace6a19",
      "name": "RocketReach Lookup Profile",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "maxTries": 3,
      "position": [
        -960,
        768
      ],
      "parameters": {
        "url": "={{ 'https://api.rocketreach.co/v2/api/lookupProfile?api_key=YOUR_API_KEY&linkedin_url=' + encodeURIComponent($json.linkedinUrl) }}",
        "options": {
          "timeout": 45000
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.3
    },
    {
      "id": "b837758e-665e-4365-94f7-9d409f65297e",
      "name": "Calculate Email Confidence",
      "type": "n8n-nodes-base.code",
      "position": [
        -736,
        768
      ],
      "parameters": {
        "jsCode": "// Grade \u2192 confidence mapping\nconst gradeToConfidence = {\n  A: 0.9,\n  B: 0.7,\n  C: 0.5,\n  D: 0.3\n};\n\nreturn items.map(item => {\n  const data = item.json;\n\n  const emails = data.emails || [];\n\n  // Prefer professional email first, then personal\n  const selectedEmail =\n    emails.find(e => e.type === 'professional') ||\n    emails.find(e => e.type === 'personal') ||\n    null;\n\n  const grade = selectedEmail?.grade || 'D';\n  const confidence = gradeToConfidence[grade] ?? 0.3;\n\n  return {\n    json: {\n      ...data,\n\n      // Normalized fields\n      selected_email: selectedEmail?.email || null,\n      email_type: selectedEmail?.type || null,\n      email_grade: grade,\n      confidence: confidence\n    }\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "b8a452e6-c0a5-4719-95be-0bda2d57a678",
      "name": "Extract AI Score Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        64,
        672
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e7279a79-c101-4e89-a5e7-ec650f8b79d2",
              "name": "score",
              "type": "number",
              "value": "={{ $json.message.content.score }}"
            },
            {
              "id": "8b3b2de9-7ba6-4e72-a06c-1a93b3ac90b5",
              "name": "priority",
              "type": "string",
              "value": "={{ $json.message.content.priority }}"
            },
            {
              "id": "6c5f124d-e4d5-4cf9-a062-2acba1062683",
              "name": "reason",
              "type": "string",
              "value": "={{ $json.message.content.reason }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "122a6c09-e437-4af1-840c-a0d60e16dcc3",
      "name": "Create Asana Task",
      "type": "n8n-nodes-base.asana",
      "position": [
        736,
        576
      ],
      "parameters": {
        "name": "Lead Added",
        "workspace": "1205967598025927",
        "authentication": "oAuth2",
        "otherProperties": {
          "notes": "={{ $json.reason }}",
          "assignee": "1212557659831213"
        }
      },
      "credentials": {
        "asanaOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bb5b92cb-b962-4bdb-a61c-3eda35700a3d",
      "name": "Notify Slack - Qualified",
      "type": "n8n-nodes-base.slack",
      "position": [
        960,
        576
      ],
      "parameters": {
        "text": "=New Lead Created in Asana !  \n\nScore:-{{ $('Extract AI Score Fields').item.json.score }}\nNotes:-{{ $json.notes }} \nAssignee:-{{ $json.assignee.name }} \n\n",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09GNB90TED",
          "cachedResultName": "general-information"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "2d0cfa50-ad63-4854-b79b-13c6a8ce2d0d",
      "name": "Notify Slack - Disqualified",
      "type": "n8n-nodes-base.slack",
      "position": [
        736,
        768
      ],
      "parameters": {
        "text": "Lead Disqualified !",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09GNB90TED",
          "cachedResultName": "general-information"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "ebfd89c3-b8c8-4d8e-84ed-cc150ad625bc",
      "name": "Workflow Error Handler",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        -1408,
        1424
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "981e8983-a2b3-49c7-be13-45be2428dc22",
      "name": "Send a message1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -1088,
        1424
      ],
      "parameters": {
        "message": "=\ud83d\udea8 *Workflow Error Alert*  *Error Node:* {{ $json.node.name }} *Error Message:* {{ $json.error.message }} *Timestamp:* {{ $now.toISO() }}  Please investigate immediately.",
        "options": {},
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "67c203e4-740e-4f55-b6d0-0c194153e448",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1472,
        1232
      ],
      "parameters": {
        "color": 3,
        "width": 672,
        "height": 336,
        "content": "## \ud83d\udea8 Error Handling \n\n \nCatches any workflow failure and posts an alert to Gmail.  \nIncludes node name, error message, and timestamp for quick debugging.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "6cdec5d6-8db1-49ea-a71c-43d05e1ef336",
  "connections": {
    "Score Filter": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond - Low Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Quality Filter": {
      "main": [
        [
          {
            "node": "AI Lead Scoring",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond - Low Confidence",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Lead Scoring": {
      "main": [
        [
          {
            "node": "Extract AI Score Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Normalize Lead Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Asana Task": {
      "main": [
        [
          {
            "node": "Notify Slack - Qualified",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Webhook": {
      "main": [
        [
          {
            "node": "Create Asana Task",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Lead Data": {
      "main": [
        [
          {
            "node": "RocketReach Lookup Profile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond - Low Score": {
      "main": [
        [
          {
            "node": "Notify Slack - Disqualified",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Error Handler": {
      "main": [
        [
          {
            "node": "Send a message1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract AI Score Fields": {
      "main": [
        [
          {
            "node": "Score Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Email Confidence": {
      "main": [
        [
          {
            "node": "Quality Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RocketReach Lookup Profile": {
      "main": [
        [
          {
            "node": "Calculate Email Confidence",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}