This workflow follows the Error Trigger → Gmail recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "AI Lead Qualification & Follow-Up",
"nodes": [
{
"parameters": {
"content": "## AI Lead Qualification & Follow-Up\n\nThis workflow:\n1. Receives lead data via Webhook\n2. Validates required fields\n3. Uses OpenAI to score (0-100) and classify the lead\n4. Routes: Hot (>=75) \u2192 Slack, Warm (>=50) \u2192 CRM, Cold \u2192 Nurture sheet\n5. Requires human approval before sending follow-up email\n6. Sends personalized follow-up via Gmail\n\n**Setup required:**\n- Webhook URL (auto-generated)\n- OpenAI API credential\n- Slack credential\n- CRM HTTP endpoint\n- Gmail OAuth2 credential\n- Google Sheets credential\n\n**Payload expected:**\n```json\n{\n \"first_name\": \"Jane\",\n \"last_name\": \"Doe\",\n \"email\": \"jane@company.com\",\n \"company\": \"Acme Corp\",\n \"job_title\": \"CTO\",\n \"industry\": \"SaaS\",\n \"company_size\": \"50-200\",\n \"source\": \"Website\",\n \"message\": \"Interested in enterprise plan\",\n \"budget\": \"$5000/month\",\n \"timeline\": \"Q1 2025\"\n}\n```",
"height": 500,
"width": 420,
"color": 5
},
"id": "c2b3d4e5-0002-4000-8000-000000000001",
"name": "Sticky Note - Overview",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
240,
-360
]
},
{
"parameters": {
"content": "## AI Scoring Logic\n\nOpenAI scores leads 0-100 based on:\n- **Job Title / Seniority** (decision maker?)\n- **Company Size** (ICP fit?)\n- **Industry** (target vertical?)\n- **Budget** (affordable?)\n- **Timeline** (buying soon?)\n- **Message Intent** (high interest?)\n\n**Classification:**\n- 75-100 = `hot` \u2192 Immediate Slack + fast-track\n- 50-74 = `warm` \u2192 CRM entry + nurture\n- 0-49 = `cold` \u2192 Google Sheets nurture list",
"height": 340,
"width": 380,
"color": 3
},
"id": "c2b3d4e5-0002-4000-8000-000000000002",
"name": "Sticky Note - Scoring",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
700,
-360
]
},
{
"parameters": {
"content": "## Human Approval Gate\n\nBefore sending any follow-up email, the workflow pauses and waits for a human to approve via the n8n UI or a webhook callback.\n\nThe approver reviews:\n- Lead score\n- AI-generated email draft\n- Lead classification\n\nApprove or reject within the n8n execution UI.",
"height": 240,
"width": 340,
"color": 4
},
"id": "c2b3d4e5-0002-4000-8000-000000000003",
"name": "Sticky Note - Approval",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1600,
-360
]
},
{
"parameters": {
"httpMethod": "POST",
"path": "lead-qualification",
"authentication": "none",
"responseMode": "responseNode",
"options": {
"ignoreBots": false,
"rawBody": false
}
},
"id": "c2b3d4e5-0002-4000-8000-000000000004",
"name": "Webhook - Receive Lead",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
160
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "val-001",
"name": "first_name",
"value": "={{ $json.body?.first_name || $json.first_name || 'Unknown' }}",
"type": "string"
},
{
"id": "val-002",
"name": "last_name",
"value": "={{ $json.body?.last_name || $json.last_name || '' }}",
"type": "string"
},
{
"id": "val-003",
"name": "email",
"value": "={{ $json.body?.email || $json.email || '' }}",
"type": "string"
},
{
"id": "val-004",
"name": "company",
"value": "={{ $json.body?.company || $json.company || 'not mentioned' }}",
"type": "string"
},
{
"id": "val-005",
"name": "job_title",
"value": "={{ $json.body?.job_title || $json.job_title || 'not mentioned' }}",
"type": "string"
},
{
"id": "val-006",
"name": "industry",
"value": "={{ $json.body?.industry || $json.industry || 'not mentioned' }}",
"type": "string"
},
{
"id": "val-007",
"name": "company_size",
"value": "={{ $json.body?.company_size || $json.company_size || 'not mentioned' }}",
"type": "string"
},
{
"id": "val-008",
"name": "source",
"value": "={{ $json.body?.source || $json.source || 'unknown' }}",
"type": "string"
},
{
"id": "val-009",
"name": "message",
"value": "={{ $json.body?.message || $json.message || '' }}",
"type": "string"
},
{
"id": "val-010",
"name": "budget",
"value": "={{ $json.body?.budget || $json.budget || 'not mentioned' }}",
"type": "string"
},
{
"id": "val-011",
"name": "timeline",
"value": "={{ $json.body?.timeline || $json.timeline || 'not mentioned' }}",
"type": "string"
},
{
"id": "val-012",
"name": "received_at",
"value": "={{ $now.toISO() }}",
"type": "string"
}
]
},
"options": {}
},
"id": "c2b3d4e5-0002-4000-8000-000000000005",
"name": "Set - Validate & Normalize Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
480,
160
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.openai.com/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.3,\n \"response_format\": { \"type\": \"json_object\" },\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are an AI automation assistant inside a business workflow. Use only the provided input. Do not invent details. If information is missing, return 'unknown' or 'not mentioned'. Always return valid JSON matching the requested schema.\"\n },\n {\n \"role\": \"user\",\n \"content\": \"You are a B2B sales qualification AI. Analyze this lead and return a JSON object with:\\n\\n- score: integer 0-100 (higher = better qualified)\\n- classification: string, one of 'hot', 'warm', or 'cold'\\n- reasoning: string explaining the score in 1-2 sentences\\n- strengths: array of up to 3 strings identifying positive signals\\n- concerns: array of up to 3 strings identifying risk factors or missing info\\n- follow_up_email: object with fields: subject (string), body (string, use \\\\n for newlines, personalized, professional, under 200 words)\\n\\nScoring criteria:\\n- Job seniority and decision-making authority: up to 25 points\\n- Company size alignment with ICP: up to 20 points\\n- Industry fit: up to 15 points\\n- Budget clarity and adequacy: up to 20 points\\n- Timeline urgency: up to 10 points\\n- Message intent and engagement level: up to 10 points\\n\\nLead Data:\\nName: {{ $json.first_name }} {{ $json.last_name }}\\nEmail: {{ $json.email }}\\nCompany: {{ $json.company }}\\nJob Title: {{ $json.job_title }}\\nIndustry: {{ $json.industry }}\\nCompany Size: {{ $json.company_size }}\\nLead Source: {{ $json.source }}\\nMessage: {{ $json.message }}\\nBudget: {{ $json.budget }}\\nTimeline: {{ $json.timeline }}\"\n }\n ]\n}",
"options": {
"timeout": 45000
}
},
"id": "c2b3d4e5-0002-4000-8000-000000000006",
"name": "OpenAI - Score & Generate Follow-Up",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
720,
160
],
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 3000,
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "parse-001",
"name": "lead_score",
"value": "={{ JSON.parse($json.choices[0].message.content).score }}",
"type": "number"
},
{
"id": "parse-002",
"name": "lead_classification",
"value": "={{ JSON.parse($json.choices[0].message.content).classification }}",
"type": "string"
},
{
"id": "parse-003",
"name": "reasoning",
"value": "={{ JSON.parse($json.choices[0].message.content).reasoning }}",
"type": "string"
},
{
"id": "parse-004",
"name": "strengths",
"value": "={{ JSON.parse($json.choices[0].message.content).strengths }}",
"type": "array"
},
{
"id": "parse-005",
"name": "concerns",
"value": "={{ JSON.parse($json.choices[0].message.content).concerns }}",
"type": "array"
},
{
"id": "parse-006",
"name": "follow_up_subject",
"value": "={{ JSON.parse($json.choices[0].message.content).follow_up_email.subject }}",
"type": "string"
},
{
"id": "parse-007",
"name": "follow_up_body",
"value": "={{ JSON.parse($json.choices[0].message.content).follow_up_email.body }}",
"type": "string"
},
{
"id": "parse-008",
"name": "first_name",
"value": "={{ $('Set - Validate & Normalize Fields').item.json.first_name }}",
"type": "string"
},
{
"id": "parse-009",
"name": "email",
"value": "={{ $('Set - Validate & Normalize Fields').item.json.email }}",
"type": "string"
},
{
"id": "parse-010",
"name": "company",
"value": "={{ $('Set - Validate & Normalize Fields').item.json.company }}",
"type": "string"
},
{
"id": "parse-011",
"name": "received_at",
"value": "={{ $('Set - Validate & Normalize Fields').item.json.received_at }}",
"type": "string"
}
]
},
"options": {}
},
"id": "c2b3d4e5-0002-4000-8000-000000000007",
"name": "Set - Parse AI Response",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
960,
160
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-hot",
"leftValue": "={{ $json.lead_score }}",
"rightValue": 75,
"operator": {
"type": "number",
"operation": "gte"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "c2b3d4e5-0002-4000-8000-000000000008",
"name": "IF - Score >= 75 (Hot)",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1200,
160
]
},
{
"parameters": {
"authentication": "oAuth2",
"resource": "message",
"operation": "post",
"channel": {
"__rl": true,
"value": "#hot-leads",
"mode": "name"
},
"text": "=:fire: *HOT LEAD ALERT* :fire:\n\n*Score:* {{ $json.lead_score }}/100 | *Classification:* {{ $json.lead_classification.toUpperCase() }}\n\n*Name:* {{ $json.first_name }}\n*Company:* {{ $json.company }}\n*Email:* {{ $json.email }}\n\n*AI Reasoning:* {{ $json.reasoning }}\n\n*Strengths:*\n{{ $json.strengths.map(s => `\u2022 ${s}`).join('\\n') }}\n\n*Concerns:*\n{{ $json.concerns.map(c => `\u2022 ${c}`).join('\\n') }}\n\n:point_right: Approve follow-up email in n8n before it sends.",
"otherOptions": {
"mrkdwn": true
}
},
"id": "c2b3d4e5-0002-4000-8000-000000000009",
"name": "Slack - Notify Hot Lead",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
1440,
60
],
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-warm",
"leftValue": "={{ $json.lead_score }}",
"rightValue": 50,
"operator": {
"type": "number",
"operation": "gte"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "c2b3d4e5-0002-4000-8000-000000000010",
"name": "IF - Score >= 50 (Warm)",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1440,
300
]
},
{
"parameters": {
"method": "POST",
"url": "https://your-crm.example.com/api/leads",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"specifyBody": "json",
"jsonBody": "={\n \"first_name\": \"{{ $json.first_name }}\",\n \"email\": \"{{ $json.email }}\",\n \"company\": \"{{ $json.company }}\",\n \"score\": {{ $json.lead_score }},\n \"classification\": \"{{ $json.lead_classification }}\",\n \"source\": \"n8n-workflow\",\n \"notes\": \"{{ $json.reasoning }}\",\n \"created_at\": \"{{ $json.received_at }}\"\n}",
"options": {
"timeout": 15000
}
},
"id": "c2b3d4e5-0002-4000-8000-000000000011",
"name": "HTTP - Add to CRM (Warm)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1680,
220
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "appendOrUpdate",
"documentId": {
"__rl": true,
"value": "YOUR_GOOGLE_SHEET_ID_HERE",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Nurture List",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Timestamp": "={{ $now.toISO() }}",
"First Name": "={{ $json.first_name }}",
"Email": "={{ $json.email }}",
"Company": "={{ $json.company }}",
"Score": "={{ $json.lead_score }}",
"Classification": "={{ $json.lead_classification }}",
"Reasoning": "={{ $json.reasoning }}",
"Follow-Up Subject": "={{ $json.follow_up_subject }}"
},
"matchingColumns": [
"Email"
],
"schema": []
},
"options": {}
},
"id": "c2b3d4e5-0002-4000-8000-000000000012",
"name": "Google Sheets - Add to Nurture",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1680,
400
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resume": "webhook",
"options": {
"webhookSuffix": "approve-lead-followup",
"responseCode": 200,
"responseData": "firstEntryJson",
"limitWaitTime": true,
"limitType": "afterTimeInterval",
"resumeAmount": 24,
"resumeUnit": "hours"
}
},
"id": "c2b3d4e5-0002-4000-8000-000000000013",
"name": "Wait - Human Approval",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1920,
60
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-approved",
"leftValue": "={{ $json.body?.approved || $json.approved }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "c2b3d4e5-0002-4000-8000-000000000014",
"name": "IF - Approved",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
2160,
60
]
},
{
"parameters": {
"sendTo": "={{ $('Set - Parse AI Response').item.json.email }}",
"subject": "={{ $('Set - Parse AI Response').item.json.follow_up_subject }}",
"emailType": "text",
"message": "={{ $('Set - Parse AI Response').item.json.follow_up_body }}",
"options": {}
},
"id": "c2b3d4e5-0002-4000-8000-000000000015",
"name": "Gmail - Send Follow-Up Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
2400,
0
],
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"authentication": "oAuth2",
"resource": "message",
"operation": "post",
"channel": {
"__rl": true,
"value": "#hot-leads",
"mode": "name"
},
"text": "=:x: *Follow-Up Rejected* \u2014 Lead not approved for follow-up.\n*Lead:* {{ $('Set - Parse AI Response').item.json.first_name }} | *Company:* {{ $('Set - Parse AI Response').item.json.company }}\nNo email sent.",
"otherOptions": {
"mrkdwn": true
}
},
"id": "c2b3d4e5-0002-4000-8000-000000000016",
"name": "Slack - Notify Rejected",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
2400,
140
],
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {},
"id": "c2b3d4e5-0002-4000-8000-000000000017",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"typeVersion": 1,
"position": [
240,
500
]
},
{
"parameters": {
"authentication": "oAuth2",
"resource": "message",
"operation": "post",
"channel": {
"__rl": true,
"value": "#workflow-errors",
"mode": "name"
},
"text": "=:x: *Workflow Error: AI Lead Qualification*\n\n*Error:* {{ $json.execution.error.message }}\n*Node:* {{ $json.execution.lastNodeExecuted }}\n*Execution ID:* {{ $json.execution.id }}\n*Time:* {{ $now.toISO() }}",
"otherOptions": {
"mrkdwn": true
}
},
"id": "c2b3d4e5-0002-4000-8000-000000000018",
"name": "Slack - Error Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
480,
500
],
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Webhook - Receive Lead": {
"main": [
[
{
"node": "Set - Validate & Normalize Fields",
"type": "main",
"index": 0
}
]
]
},
"Set - Validate & Normalize Fields": {
"main": [
[
{
"node": "OpenAI - Score & Generate Follow-Up",
"type": "main",
"index": 0
}
]
]
},
"OpenAI - Score & Generate Follow-Up": {
"main": [
[
{
"node": "Set - Parse AI Response",
"type": "main",
"index": 0
}
]
]
},
"Set - Parse AI Response": {
"main": [
[
{
"node": "IF - Score >= 75 (Hot)",
"type": "main",
"index": 0
}
]
]
},
"IF - Score >= 75 (Hot)": {
"main": [
[
{
"node": "Slack - Notify Hot Lead",
"type": "main",
"index": 0
}
],
[
{
"node": "IF - Score >= 50 (Warm)",
"type": "main",
"index": 0
}
]
]
},
"Slack - Notify Hot Lead": {
"main": [
[
{
"node": "Wait - Human Approval",
"type": "main",
"index": 0
}
]
]
},
"IF - Score >= 50 (Warm)": {
"main": [
[
{
"node": "HTTP - Add to CRM (Warm)",
"type": "main",
"index": 0
}
],
[
{
"node": "Google Sheets - Add to Nurture",
"type": "main",
"index": 0
}
]
]
},
"Wait - Human Approval": {
"main": [
[
{
"node": "IF - Approved",
"type": "main",
"index": 0
}
]
]
},
"IF - Approved": {
"main": [
[
{
"node": "Gmail - Send Follow-Up Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack - Notify Rejected",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Slack - Error Alert",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "",
"saveExecutionProgress": true,
"saveDataSuccessExecution": "all",
"saveDataErrorExecution": "all",
"timezone": "UTC"
},
"staticData": null,
"tags": [
{
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"id": "tag-lead-ai",
"name": "AI Automation"
},
{
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z",
"id": "tag-sales",
"name": "Sales"
}
],
"triggerCount": 1,
"updatedAt": "2025-01-01T00:00:00.000Z",
"versionId": "v1.0.0",
"active": false
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2googleSheetsOAuth2ApihttpHeaderAuthslackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AI Lead Qualification & Follow-Up. Uses httpRequest, slack, googleSheets, gmail. Webhook trigger; 18 nodes.
Source: https://github.com/humayun-sarfraz/n8n-ai-workflow-kit/blob/main/workflows/02-ai-lead-qualification-and-follow-up.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
AI LeadOps Main. Uses httpRequest, googleSheets, slack, gmail. Webhook trigger; 19 nodes.
Run professional email campaigns with A/B testing, Google Sheets tracking, and Slack analytics. FEATURES:
Universal Lead Processing Workflow. Uses googleSheets, gmail, httpRequest, gmailTrigger. Webhook trigger; 34 nodes.
This workflow acts as an instant SDR that replies to new inbound leads across multiple channels in real time. It first captures and normalizes all incoming lead data into a unified structure. The work
A comprehensive n8n workflow template for streamlining influencer application processing with real-time social media data validation, intelligent scoring algorithms, and automated onboarding workflows