This workflow follows the Agent → 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 →
{
"id": "o7Cj6FMfaXx3li9E",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Supplier Consolidation Recommendation Workflow",
"tags": [],
"nodes": [
{
"id": "23210f3a-8214-4b2f-9793-a219d361c998",
"name": "Supplier Analysis Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-448,
-96
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.3
},
{
"id": "7f314f03-00b0-4e70-8c78-09fc4b89e716",
"name": "Fetch Supplier Data",
"type": "n8n-nodes-base.googleSheets",
"position": [
-240,
-96
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sRjC7JdVLukXBJTJXfz-4Pa8cLxOWwIkcRxQxaw5sfo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1sRjC7JdVLukXBJTJXfz-4Pa8cLxOWwIkcRxQxaw5sfo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sRjC7JdVLukXBJTJXfz-4Pa8cLxOWwIkcRxQxaw5sfo/edit?usp=drivesdk",
"cachedResultName": "supplier records"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "0b463ce5-8531-4d6f-b05b-f3e19bccc82a",
"name": "Clean & Structure Supplier Data",
"type": "n8n-nodes-base.set",
"position": [
-32,
-96
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "7b192d94-2a9d-4b5b-b623-0494116a4d8d",
"name": "Name",
"type": "string",
"value": "={{ $json.Name }}"
},
{
"id": "6abe4c89-a4c3-4cae-a587-d24d4f96aeff",
"name": "Department",
"type": "string",
"value": "={{ $json.Department }}"
},
{
"id": "51ca714e-b6b0-4a60-84a7-94a6b5b4279d",
"name": "Category",
"type": "string",
"value": "={{ $json.Category }}"
},
{
"id": "8038adc3-fb66-47c2-bf70-4919d9a42296",
"name": "Monthly_Spend",
"type": "number",
"value": "={{ $json.Monthly_Spend }}"
},
{
"id": "1c1c59e5-8ede-4eda-8753-84f74fd95bbe",
"name": "Risk_Rating",
"type": "string",
"value": "={{ $json.Risk_Rating }}"
},
{
"id": "770b532b-da54-4a77-8afd-ce1388b04e76",
"name": "Service_Criticality",
"type": "string",
"value": "={{ $json.Service_Criticality }}"
},
{
"id": "8bd49380-56ae-41bf-86c9-ad9217924309",
"name": "Backup_Supplier_Available",
"type": "string",
"value": "={{ $json.Backup_Supplier_Available }}"
},
{
"id": "261a43f8-05f3-4dde-bcbc-d7dc9b7adc9c",
"name": "Email",
"type": "string",
"value": "={{ $json.Email }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "cfbd85ac-60c1-472a-8403-bd679ca156b5",
"name": "Identify Overlaps & Calculate Savings",
"type": "n8n-nodes-base.code",
"position": [
192,
-96
],
"parameters": {
"jsCode": "function normalize(name) {\n if (!name) return '';\n\n return name\n .toLowerCase()\n .replace(/\\b(pvt ltd|ltd|inc|technologies|tech)\\b/g, '')\n .replace(/[^\\w\\s]/g, '')\n .trim();\n}\n\nconst grouped = {};\n\nfor (const item of items) {\n const rawName = item.json.Name || '';\n const normalizedName = normalize(rawName);\n const department = item.json.Department || 'Unknown';\n const spend = Number(item.json.Monthly_Spend || 0);\n const email = item.json.Email || '';\n\n if (!normalizedName) continue;\n\n if (!grouped[normalizedName]) {\n grouped[normalizedName] = {\n supplier: rawName,\n departments: new Set(),\n emails: new Set(),\n total_spend: 0\n };\n }\n\n grouped[normalizedName].departments.add(department);\n\n if (email) {\n grouped[normalizedName].emails.add(email);\n }\n\n grouped[normalizedName].total_spend += spend;\n}\n\nconst result = [];\n\nfor (const key in grouped) {\n const data = grouped[key];\n const departmentCount = data.departments.size;\n const totalSpend = data.total_spend;\n\n if (departmentCount > 1) {\n let savingsPercent = 0;\n\n // Dynamic savings logic\n if (departmentCount >= 4 && totalSpend > 100000) {\n savingsPercent = 12;\n } else if (departmentCount >= 3 && totalSpend > 50000) {\n savingsPercent = 10;\n } else if (departmentCount >= 3) {\n savingsPercent = 8;\n } else if (departmentCount === 2 && totalSpend > 30000) {\n savingsPercent = 6;\n } else if (departmentCount === 2) {\n savingsPercent = 4;\n } else {\n savingsPercent = 2;\n }\n\n const savingsAmount = (totalSpend * savingsPercent) / 100;\n\n let opportunityLevel = 'Low';\n if (savingsPercent >= 10) {\n opportunityLevel = 'High';\n } else if (savingsPercent >= 5) {\n opportunityLevel = 'Medium';\n }\n\n result.push({\n json: {\n supplier: data.supplier,\n departments: [...data.departments].join(', '),\n email: [...data.emails].join(', '),\n department_count: departmentCount,\n total_spend: totalSpend,\n savings_percent: savingsPercent,\n savings_amount: savingsAmount,\n opportunity_level: opportunityLevel\n }\n });\n }\n}\n\nreturn result;"
},
"typeVersion": 2
},
{
"id": "c984b28b-7e02-4dff-84b5-d143282f5430",
"name": "Evaluate Risk vs Savings",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
416,
96
],
"parameters": {
"text": "=You are a procurement expert.\n\nAnalyze this supplier consolidation opportunity:\n\nSupplier: {{$json.supplier}}\nDepartments: {{$json.departments}}\nDepartment Count: {{$json.department_count}}\nTotal Spend: {{$json.total_spend}}\nSavings Percent: {{$json.savings_percent}}\nSavings Amount: {{$json.savings_amount}}\nOpportunity Level: {{$json.opportunity_level}}\n\nReturn ONLY raw JSON.\nDo not add markdown.\nDo not use code fences.\nDo not add any explanation before or after JSON.\n\nUse exactly this structure:\n{\n \"risk\": \"Low or Medium or High\",\n \"decision\": \"Recommended or Not Recommended\",\n \"recommendation\": \"short recommendation\",\n \"reason\": \"short explanation\"\n}",
"options": {},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "c7091f4c-c1c2-4336-869a-dbc08e0a5576",
"name": "Extract AI Insights",
"type": "n8n-nodes-base.code",
"position": [
720,
96
],
"parameters": {
"jsCode": "return items.map(item => {\n const raw = item.json.output || '{}';\n\n let parsed = {};\n\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n parsed = {\n risk: 'Unknown',\n decision: 'Error',\n recommendation: 'Parsing failed',\n reason: 'The AI response was not valid JSON'\n };\n }\n\n return {\n json: {\n ...item.json,\n risk: parsed.risk,\n decision: parsed.decision,\n recommendation: parsed.recommendation,\n reason: parsed.reason\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "b89186dd-037c-4eaa-907c-9bfd0362c7d6",
"name": "Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
400,
288
],
"parameters": {
"model": "openai/gpt-oss-120b",
"options": {}
},
"credentials": {
"groqApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "d7884d4b-da1e-4b1f-8612-b58df584045d",
"name": "Combine Supplier & AI Data",
"type": "n8n-nodes-base.merge",
"position": [
976,
-112
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "b6c0ed69-a69b-4bcf-b48d-d2c09d3d2463",
"name": "Prepare Final Recommendation",
"type": "n8n-nodes-base.set",
"position": [
1184,
-112
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "5eeb525f-560a-4997-8717-e2a51fea569c",
"name": "Supplier",
"type": "string",
"value": "={{ $json.supplier }}"
},
{
"id": "51e7253b-d5cf-4e9e-8584-05b88c24ed5d",
"name": "departments",
"type": "string",
"value": "={{ $json.departments }}"
},
{
"id": "57878f30-984b-4351-9a7d-2c582948d6a7",
"name": "department_count",
"type": "number",
"value": "={{ $json.department_count }}"
},
{
"id": "88d3b5b6-3a32-475a-a156-4c3530c80280",
"name": "total_spend",
"type": "number",
"value": "={{ $json.total_spend }}"
},
{
"id": "8e772d39-b286-4e9f-a03f-f303bd4461af",
"name": "savings_percent",
"type": "number",
"value": "={{ $json.savings_percent }}"
},
{
"id": "ac1a69b9-b5d2-416e-84a5-d18cf38e378d",
"name": "savings_amount",
"type": "number",
"value": "={{ $json.savings_amount }}"
},
{
"id": "fb18dbfb-15cc-4b39-b0c3-ce4749dcbfe8",
"name": "risk",
"type": "string",
"value": "={{ $json.risk }}"
},
{
"id": "0f8f15c0-ac91-4226-b4ea-b9f187b47508",
"name": "decision",
"type": "string",
"value": "={{ $json.decision }}"
},
{
"id": "044686a4-4220-44f6-b810-8ec322e21f81",
"name": "recommendation",
"type": "string",
"value": "={{ $json.recommendation }}"
},
{
"id": "6b455ff4-3784-4cd8-9968-53f98057dc98",
"name": "reason",
"type": "string",
"value": "={{ $json.reason }}"
},
{
"id": "5f3d80fb-7504-4531-bc9c-825c1018cd86",
"name": "Email",
"type": "string",
"value": "={{$json.email}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ba3a8d47-cc77-48e6-8bfc-72812be74366",
"name": "Send Slack Alert",
"type": "n8n-nodes-base.slack",
"position": [
1472,
-192
],
"parameters": {
"text": "=Supplier Consolidation Recommendation \nSupplier: {{$json.Supplier}} \nDepartments: {{ $json.departments }} \nDepartment Count: {{ $json.department_count }} \nTotal Spend: {{ $json.total_spend }}\nSavings Percent: {{ $json.savings_percent }}\nSavings Amount: {{ $json.savings_amount }}\nRisk: {{ $json.risk }}\nDecision:{{ $json.decision }}\nRecommendation: {{ $json.recommendation }}\nReason: {{ $json.reason }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C0ATE2C0ZTN",
"cachedResultName": "supplier-insights"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "69785bcd-cb7c-4c1c-83ed-fa10b0ef8052",
"name": "Send Email Report",
"type": "n8n-nodes-base.gmail",
"position": [
1472,
16
],
"parameters": {
"sendTo": "={{ $json.Email }}",
"message": "=<div style=\"font-family: Arial, sans-serif; line-height: 1.6; color: #222;\">\n <h2 style=\"margin-bottom: 10px;\">Supplier Consolidation Recommendation</h2>\n\n <p><strong>Supplier:</strong> {{$json.Supplier}}</p>\n <p><strong>Departments:</strong> {{$json.departments}}</p>\n <p><strong>Department Count:</strong> {{$json.department_count}}</p>\n\n <hr style=\"border: none; border-top: 1px solid #ddd; margin: 16px 0;\">\n\n <p><strong>Total Spend:</strong> {{$json.total_spend}}</p>\n <p><strong>Savings Percent:</strong> {{$json.savings_percent}}%</p>\n <p><strong>Savings Amount:</strong> {{$json.savings_amount}}</p>\n\n <hr style=\"border: none; border-top: 1px solid #ddd; margin: 16px 0;\">\n\n <p><strong>Risk Level:</strong> {{$json.risk}}</p>\n <p><strong>Decision:</strong> {{$json.decision}}</p>\n\n <p><strong>Recommendation:</strong><br>{{$json.recommendation}}</p>\n\n <p><strong>Reason:</strong><br>{{$json.reason}}</p>\n\n <br>\n\n <p>Regards,<br>Procurement Automation System</p>\n</div>",
"options": {
"appendAttribution": false
},
"subject": "=Supplier Consolidation Recommendation - {{$json.Supplier}}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "342c2e14-4477-415d-a0a4-eb0b7dee8542",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-960,
-368
],
"parameters": {
"width": 384,
"height": 800,
"content": "# Supplier Consolidation Recommendation \n\n# How it works:\n\nThis workflow identifies overlapping suppliers, estimates savings, and uses AI to evaluate risk versus savings before generating recommendations. Final insights are shared via email and Slack for quick decision-making.\n\n# Setup Steps:\n1. Scheduled Trigger\nRun workflow weekly.\n\n2. Data Collection\nFetch supplier data from Google Sheets.\n\n3. Overlap & Savings Detection\nIdentify shared suppliers and calculate savings.\n\n4. AI Analysis\nEvaluate risk vs savings.\n\n5. Data Processing\nCombine and format results.\n\n6. Output & Notification\nSend email and Slack alerts.\n"
},
"typeVersion": 1
},
{
"id": "f6629d33-19c6-412e-b444-78760658b58b",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-544,
-288
],
"parameters": {
"color": 7,
"width": 656,
"height": 416,
"content": "## Supplier Data Collection & Preparation\n\nTrigger the workflow on schedule, fetch supplier records from Google Sheets, and clean/structure key fields like department, spend, and email to prepare data for analysis."
},
"typeVersion": 1
},
{
"id": "0f71abc3-a9bf-4912-af1d-7bfeb642e1ba",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
144,
-288
],
"parameters": {
"color": 7,
"width": 720,
"height": 688,
"content": "\n## Supplier Analysis & AI Insights\n\nIdentify overlapping suppliers across departments and calculate potential savings. Use AI to evaluate risk versus savings and extract structured insights for decision-making."
},
"typeVersion": 1
},
{
"id": "2f12fc66-4376-4f10-9225-070412ccf133",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
896,
-288
],
"parameters": {
"color": 7,
"width": 816,
"height": 672,
"content": "## Final Recommendation & Notifications\nCombine supplier and AI data, format the final recommendation, and send insights to stakeholders via Slack alerts and dynamic email reports for quick action."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "006398fa-b4ba-441f-afa7-58c8f2fd27ed",
"connections": {
"Chat Model": {
"ai_languageModel": [
[
{
"node": "Evaluate Risk vs Savings",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Extract AI Insights": {
"main": [
[
{
"node": "Combine Supplier & AI Data",
"type": "main",
"index": 1
}
]
]
},
"Fetch Supplier Data": {
"main": [
[
{
"node": "Clean & Structure Supplier Data",
"type": "main",
"index": 0
}
]
]
},
"Evaluate Risk vs Savings": {
"main": [
[
{
"node": "Extract AI Insights",
"type": "main",
"index": 0
}
]
]
},
"Supplier Analysis Trigger": {
"main": [
[
{
"node": "Fetch Supplier Data",
"type": "main",
"index": 0
}
]
]
},
"Combine Supplier & AI Data": {
"main": [
[
{
"node": "Prepare Final Recommendation",
"type": "main",
"index": 0
}
]
]
},
"Prepare Final Recommendation": {
"main": [
[
{
"node": "Send Slack Alert",
"type": "main",
"index": 0
},
{
"node": "Send Email Report",
"type": "main",
"index": 0
}
]
]
},
"Clean & Structure Supplier Data": {
"main": [
[
{
"node": "Identify Overlaps & Calculate Savings",
"type": "main",
"index": 0
}
]
]
},
"Identify Overlaps & Calculate Savings": {
"main": [
[
{
"node": "Evaluate Risk vs Savings",
"type": "main",
"index": 0
},
{
"node": "Combine Supplier & AI Data",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
gmailOAuth2googleSheetsOAuth2ApigroqApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Supplier Consolidation Recommendation Workflow. Uses googleSheets, agent, lmChatGroq, slack. Scheduled trigger; 15 nodes.
Source: https://github.com/weblineindia/n8n-Recommend-supplier-consolidation-with-Google-Sheets-Groq-Slack-and-Gmail/blob/main/workflow-template.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.
Supplier Capacity Risk Alert Workflow. Uses httpRequest, lmChatGroq, agent, gmail. Scheduled trigger; 28 nodes.
Created by: Peyton Leveillee Last updated: October 2025
This workflow automates invoicing and payment follow-ups using Google Sheets, PDFShift, Groq (LLM), Gmail, and Telegram, sending initial invoices with PDF attachments, scheduling overdue reminders at
Categories Content Creation AI Automation Publishing Social Media
This workflow automates end-to-end ESG (Environmental, Social, and Governance) sustainability reporting for enterprise sustainability teams, compliance officers, and green governance leads. It solves