This workflow corresponds to n8n.io template #12027 — we link there as the canonical source.
This workflow follows the HTTP Request → OpenAI 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": "EXVYD8hh4mxxOE7M",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Zoho Deal Forecasting with External Market Factor",
"tags": [],
"nodes": [
{
"id": "3b868d38-174b-43f7-bfce-d5639864534a",
"name": "Get Market Signal1",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1040,
-1296
],
"parameters": {
"url": "https://www.alphavantage.co/query",
"options": {},
"queryParametersUi": {
"parameter": [
{
"name": "function",
"value": "GLOBAL_QUOTE"
},
{
"name": "symbol",
"value": "SPY"
},
{
"name": "apikey",
"value": "{{Your_Alphavantage_API_key}}"
}
]
}
},
"typeVersion": 2
},
{
"id": "ebebe4b3-0701-4471-9cce-ebbf45c03613",
"name": "Update Deal Forecast1",
"type": "n8n-nodes-base.zohoCrm",
"position": [
592,
-1280
],
"parameters": {
"dealId": "={{ $json.id }}",
"resource": "deal",
"operation": "update",
"updateFields": {
"Amount": "={{ $json.Amount }}",
"customFields": {
"customFields": [
{
"value": "={{ $json.Market_Signal }}",
"fieldId": "Market_Signal"
},
{
"value": "={{ $json.Seasonal_Factor }}",
"fieldId": "Seasonal_Factor"
},
{
"value": "={{ $json.Market_Seasonal_Adjusted_Forecast }}",
"fieldId": "Market_Signal_Adjust_forecast"
},
{
"value": "={{ $json.Expected_Revenue }}",
"fieldId": "Revenue"
}
]
}
}
},
"credentials": {
"zohoOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "f7238560-a165-47a0-8503-543f76ae3aaf",
"name": "Send Forecast Summary1",
"type": "n8n-nodes-base.slack",
"position": [
864,
-1280
],
"parameters": {
"text": "=Deal Forecast Updated (AI-Enhanced)\n\nDeal: {{ $('Merge Forecast & AI data').item.json.Deal_Name }}\nStage: {{ $('Merge Forecast & AI data').item.json.Stage }}\nAmount: {{ $('Merge Forecast & AI data').item.json.Amount }}\n\nMarket Signal: {{ $('Merge Forecast & AI data').item.json.Market_Signal }}\nSeasonal Factor: {{ $('Merge Forecast & AI data').item.json.Seasonal_Factor }}\n\nAI Match Ratio: {{ $('Merge Forecast & AI data').item.json.match_ratio }}%\nConfidence: {{ $('Merge Forecast & AI data').item.json.confidence }}\nReason: {{ $('Merge Forecast & AI data').item.json.reason }}\n\nAdjusted Forecast: {{ $('Merge Forecast & AI data').item.json.Market_Seasonal_Adjusted_Forecast }}\n",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09S57E2JQ2",
"cachedResultName": "n8n"
},
"otherOptions": {
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "42ebde43-b13b-4a10-9c70-3ebc8b6f2662",
"name": "Fetch open Deals1",
"type": "n8n-nodes-base.zohoCrm",
"position": [
-1056,
-1696
],
"parameters": {
"options": {},
"resource": "deal",
"operation": "getAll"
},
"credentials": {
"zohoOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "9aa6b33e-884b-4953-8d35-8ddd6f7f3350",
"name": "Combine Deal & Market Info1",
"type": "n8n-nodes-base.merge",
"position": [
-688,
-1504
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "dd875384-23b8-421c-9d82-a8b35823914d",
"name": "Generate Forecast Metrics1",
"type": "n8n-nodes-base.function",
"position": [
-480,
-1504
],
"parameters": {
"functionCode": "// ----------------------\n// AI-style Dynamic Forecast Function Node\n// ----------------------\n\n// Get all items from the Merge node\nconst allItems = $input.all();\n\n// Separate current deals and historical deals\n// Assuming your \"Get Deals\" node fetches both historical and current deals\n// You can adjust historical vs current by date if needed\nconst deals = allItems\n .map(item => item.json)\n .filter(d => d.Amount && d.Probability); // basic filter\n\n// Get Market Signal\nconst marketItem = allItems.find(item => item.json.marketSignal !== undefined);\nconst marketSignal = marketItem?.json?.marketSignal || 1;\n\n// Helper function to safely parse numbers\nfunction safeNumber(value, fallback = 0) {\n if (value === null || value === undefined || value === \"\") return fallback;\n const num = parseFloat(value);\n return isNaN(num) ? fallback : num;\n}\n\n// ----------------------\n// Dynamic Seasonality Calculation\n// Using historical deal close dates to compute seasonal factors\n// ----------------------\nconst historicalDeals = deals.filter(d => d.Close_Date); // all deals with close date\nconst monthlyTotals = Array(12).fill(0);\nconst monthlyCounts = Array(12).fill(0);\n\nhistoricalDeals.forEach(d => {\n const closeMonth = new Date(d.Close_Date).getMonth(); // 0 = Jan\n const amount = safeNumber(d.Amount);\n const probability = safeNumber(d.Probability) / 100;\n monthlyTotals[closeMonth] += amount * probability;\n monthlyCounts[closeMonth] += 1;\n});\n\n// Normalize to average\nconst totalRevenue = monthlyTotals.reduce((a, b) => a + b, 0);\nconst avgRevenue = totalRevenue / 12;\nconst seasonalityFactors = monthlyTotals.map(total => (avgRevenue ? total / avgRevenue : 1));\n\n// Current month factor\nconst currentMonth = new Date().getMonth();\nconst seasonalFactor = seasonalityFactors[currentMonth] || 1;\n\n// ----------------------\n// Filter valid deals (Amount > 0 and Probability > 0)\n// ----------------------\nconst validDeals = deals.filter(d => safeNumber(d.Amount) > 0 && safeNumber(d.Probability) > 0);\n\n// ----------------------\n// Compute Forecast with Market + Seasonal Factors\n// ----------------------\nreturn validDeals.map(d => {\n const dealName = d.Deal_Name || \"Unnamed Deal\";\n const amount = safeNumber(d.Amount);\n const probability = safeNumber(d.Probability) / 100;\n\n const pipelineWeighted = amount * probability;\n const expectedRevenue = safeNumber(d.Expected_Revenue, pipelineWeighted);\n\n // AI-style adjusted forecast\n const adjustedForecast = pipelineWeighted * marketSignal * seasonalFactor;\n\n return {\n json: {\n id: d.id,\n Deal_Name: dealName,\n Stage: d.Stage,\n Amount: amount,\n Probability: probability,\n Expected_Revenue: expectedRevenue,\n Market_Signal: marketSignal,\n Seasonal_Factor: seasonalFactor,\n Market_Seasonal_Adjusted_Forecast: adjustedForecast\n }\n };\n});\n"
},
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "b0ec65c3-ae04-480f-b9c1-bff458a81baa",
"name": "Weekly Trigger1",
"type": "n8n-nodes-base.cron",
"position": [
-1424,
-1488
],
"parameters": {
"triggerTimes": {
"item": [
{
"hour": 2
}
]
}
},
"typeVersion": 1
},
{
"id": "06e67635-d308-45b2-90a7-05fe1fa5dcd4",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2016,
-1952
],
"parameters": {
"width": 416,
"height": 672,
"content": "## How it works\n\nThis workflow automatically updates your Zoho CRM deals every week with AI-enhanced forecasts. It fetches all active deals and current market signals, then calculates expected revenue using deal amount, probability, seasonality, and market trends. An AI node evaluates how well each deal matches market conditions and assigns a match ratio, confidence level, and reasoning. The workflow then updates the forecast in Zoho, stores the results in Supabase for tracking, and sends a summary to Slack so your team can quickly see deal performance and insights.\n\n## Setup steps\n\n**1.** Create required custom fields in Zoho CRM deals.\n\n**2.** Add Zoho OAuth credentials to n8n.\n\n**3.** Configure \u201cFetch open Deals\u201d node to get all active deals.\n\n**4.** Add your market API key (e.g., AlphaVantage) to the HTTP node.\n\n**5.** Replace placeholder Zoho field IDs with API names.\n\n**6.** Map Slack messages to your preferred channel.\n\n**7.** Test the workflow manually, then activate the weekly cron trigger."
},
"typeVersion": 1
},
{
"id": "6ed251fd-3d15-4dda-8d20-3d9b1b129987",
"name": "Store Forecast",
"type": "n8n-nodes-base.supabase",
"position": [
576,
-1760
],
"parameters": {
"tableId": "deal_forecast",
"fieldsUi": {
"fieldValues": [
{
"fieldId": "id",
"fieldValue": "={{ $json.id }}"
},
{
"fieldId": "deal_name",
"fieldValue": "={{ $json.Deal_Name }}"
},
{
"fieldId": "stage",
"fieldValue": "={{ $json.Stage }}"
},
{
"fieldId": "amount",
"fieldValue": "={{ $json.Amount }}"
},
{
"fieldId": "match_ratio",
"fieldValue": "={{ $json.match_ratio }}"
},
{
"fieldId": "confidence",
"fieldValue": "={{ $json.confidence }}"
},
{
"fieldId": "reason",
"fieldValue": "={{ $json.reason }}"
}
]
}
},
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "13f2aaef-7cba-4aba-9f00-67132e598c5f",
"name": "Deal Match Evaluator",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-272,
-1504
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4-turbo",
"cachedResultName": "GPT-4-TURBO"
},
"options": {},
"responses": {
"values": [
{
"content": "=You are a sales forecasting assistant.\n\nGiven the following deal data and market signal, calculate:\n\n1. Match Ratio (0\u2013100):\n - How well this deal aligns with current market conditions\n\n2. Confidence Level:\n - LOW / MEDIUM / HIGH\n\n3. One-line reasoning\n\nDeal Data:\n- Deal Amount: {{ $json.Amount }}\n- Stage: {{ $json.Stage }}\n- Probability: {{ $json.Probability }}\n- Expected Revenue: {{ $json.Expected_Revenue }}\n- Seasonal Factor: {{ $json.Seasonal_Factor }}\n\nMarket Signal:\n- Market Index Factor: {{ $json.Market_Signal }}\n\nRespond strictly in JSON:\n{\n \"match_ratio\": number,\n \"confidence\": string,\n \"reason\": string\n}\n"
}
]
},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "f2843f1a-b113-423d-af62-8b44da12ebce",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1488,
-1568
],
"parameters": {
"color": 7,
"height": 224,
"content": "Runs this workflow automatically every week."
},
"typeVersion": 1
},
{
"id": "73e7a455-0f2f-481e-81a8-e4b89ed1c6c1",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1120,
-1776
],
"parameters": {
"color": 7,
"width": 256,
"height": 240,
"content": "Fetches all active deals from Zoho that are still in early/mid pipeline stages."
},
"typeVersion": 1
},
{
"id": "bca71ab2-ecb4-4791-b90d-761514d6bec7",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1120,
-1392
],
"parameters": {
"color": 7,
"width": 256,
"height": 256,
"content": "Fetches real-time market trend data (SPY index) from AlphaVantage."
},
"typeVersion": 1
},
{
"id": "3cfe9af7-10b8-4507-91fe-51208b9610b8",
"name": "Parse AI Output",
"type": "n8n-nodes-base.code",
"position": [
32,
-1504
],
"parameters": {
"jsCode": "const items = $input.all();\n\nconst results = items.map(item => {\n const rawText =\n item.json.output?.[0]?.content?.[0]?.text || \"\";\n\n // Remove markdown wrappers\n const cleaned = rawText\n .replace(/```json/g, \"\")\n .replace(/```/g, \"\")\n .trim();\n\n let parsed;\n try {\n parsed = JSON.parse(cleaned);\n } catch (e) {\n parsed = {\n match_ratio: null,\n confidence: \"UNKNOWN\",\n reason: \"Failed to parse AI response\"\n };\n }\n\n return {\n json: {\n match_ratio: parsed.match_ratio,\n confidence: parsed.confidence,\n reason: parsed.reason\n }\n };\n});\n\nreturn results;\n"
},
"typeVersion": 2
},
{
"id": "a924816e-9de7-4b17-acc6-bbcc1ca186f1",
"name": "Merge Forecast & AI data",
"type": "n8n-nodes-base.set",
"position": [
224,
-1504
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "940a5614-1915-411a-ab0b-d3b9edf1f0a7",
"name": "id",
"type": "string",
"value": "={{ $('Generate Forecast Metrics1').item.json.id }}"
},
{
"id": "1eb06bd8-b51e-4eaf-8aa2-6dd706d2df25",
"name": "Deal_Name",
"type": "string",
"value": "={{ $('Generate Forecast Metrics1').item.json.Deal_Name }}"
},
{
"id": "2b+1234567890e5-46ae-9bd7-c5d2564c4a01",
"name": "Stage",
"type": "string",
"value": "={{ $('Generate Forecast Metrics1').item.json.Stage }}"
},
{
"id": "37fb74b6-8d27-4b99-87d3-614c560bff9c",
"name": "Amount",
"type": "number",
"value": "={{ $('Generate Forecast Metrics1').item.json.Amount }}"
},
{
"id": "0e272341-46a1-4fbe-8258-02039fd1f942",
"name": "Probability",
"type": "number",
"value": "={{ $('Generate Forecast Metrics1').item.json.Probability }}"
},
{
"id": "e8c7058e-2840-4a5d-a613-8bba4806cec7",
"name": "Expected_Revenue",
"type": "number",
"value": "={{ $('Generate Forecast Metrics1').item.json.Expected_Revenue }}"
},
{
"id": "013b3035-d4a0-4624-8552-c9da65af4c8b",
"name": "Market_Signal",
"type": "number",
"value": "={{ $('Generate Forecast Metrics1').item.json.Market_Signal }}"
},
{
"id": "eb185701-9f77-4944-a253-5631358336a0",
"name": "Seasonal_Factor",
"type": "number",
"value": "={{ $('Generate Forecast Metrics1').item.json.Seasonal_Factor }}"
},
{
"id": "cd064e36-cbef-464d-a4c5-9a12f6b2a11e",
"name": "Market_Seasonal_Adjusted_Forecast",
"type": "number",
"value": "={{ $('Generate Forecast Metrics1').item.json.Market_Seasonal_Adjusted_Forecast }}"
},
{
"id": "5482bf0a-0f81-4073-aa73-461ff9638425",
"name": "match_ratio",
"type": "number",
"value": "={{ $json.match_ratio }}"
},
{
"id": "1c024593-bed9-4d68-96bd-0abe41a7f78c",
"name": "confidence",
"type": "string",
"value": "={{ $json.confidence }}"
},
{
"id": "d0473487-a38c-454f-a5dc-3e93d1bae583",
"name": "reason",
"type": "string",
"value": "={{ $json.reason }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "6f197d7a-e472-4cf1-bfbe-7ee3c35b0b30",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-736,
-1680
],
"parameters": {
"color": 7,
"width": 1152,
"height": 400,
"content": "## Forecast Calculation Process\nThis part of the workflow collects all active deals from Zoho and real-time market signals. It calculates the expected revenue using deal amount, probability, seasonality, and market trends. An AI node then evaluates each deal\u2019s alignment with market conditions, giving a match ratio, confidence level, and reasoning. Finally, all metrics and AI insights are merged into one complete dataset ready for updating or storing."
},
"typeVersion": 1
},
{
"id": "c92830dd-a1d2-4a63-beda-92519e5d6331",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
-1856
],
"parameters": {
"color": 7,
"width": 304,
"height": 256,
"content": "This node saves all updated deal forecasts and AI insights into a database."
},
"typeVersion": 1
},
{
"id": "0c07a869-4279-402a-8e73-7badd30732a6",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
-1456
],
"parameters": {
"color": 7,
"width": 640,
"height": 368,
"content": "## Update & Share Forecast\nThis part of the workflow updates each deal in Zoho CRM with the new forecast values, including expected revenue, market signals, seasonal factors, and AI insights. After updating, it sends a summary message to Slack, so the team can quickly see the updated forecasts and deal performance."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "3063b21a-5ccf-4c60-8b54-f670f8ead15f",
"connections": {
"Parse AI Output": {
"main": [
[
{
"node": "Merge Forecast & AI data",
"type": "main",
"index": 0
}
]
]
},
"Weekly Trigger1": {
"main": [
[
{
"node": "Fetch open Deals1",
"type": "main",
"index": 0
},
{
"node": "Get Market Signal1",
"type": "main",
"index": 0
}
]
]
},
"Fetch open Deals1": {
"main": [
[
{
"node": "Combine Deal & Market Info1",
"type": "main",
"index": 0
}
]
]
},
"Get Market Signal1": {
"main": [
[
{
"node": "Combine Deal & Market Info1",
"type": "main",
"index": 1
}
]
]
},
"Deal Match Evaluator": {
"main": [
[
{
"node": "Parse AI Output",
"type": "main",
"index": 0
}
]
]
},
"Update Deal Forecast1": {
"main": [
[
{
"node": "Send Forecast Summary1",
"type": "main",
"index": 0
}
]
]
},
"Send Forecast Summary1": {
"main": [
[]
]
},
"Merge Forecast & AI data": {
"main": [
[
{
"node": "Update Deal Forecast1",
"type": "main",
"index": 0
},
{
"node": "Store Forecast",
"type": "main",
"index": 0
}
]
]
},
"Generate Forecast Metrics1": {
"main": [
[
{
"node": "Deal Match Evaluator",
"type": "main",
"index": 0
}
]
]
},
"Combine Deal & Market Info1": {
"main": [
[
{
"node": "Generate Forecast Metrics1",
"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.
openAiApislackApisupabaseApizohoOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically fetches active deals from Zoho CRM, retrieves real-time market signals, calculates AI-enhanced forecast metrics, evaluates deal-market alignment, stores data in a database, updates CRM, and sends a summary alert to Slack.
Source: https://n8n.io/workflows/12027/ — 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.
A scheduled process aggregates content from eight distinct data sources and standardizes all inputs into a unified format. AI models perform sentiment scoring, detect conspiracy or misinformation sign
Imagine a dedicated financial expert tirelessly working behind the scenes, sifting through every transaction, every investment move, and every accounting entry. That's exactly what this automated syst
Sales Team V2. Uses supabase, httpRequest, crypto, openAi. Scheduled trigger; 25 nodes.
Automate your social media content pipeline from idea to scheduled post. This workflow reads content ideas from a Google Sheet, uses OpenAI to generate platform-optimized posts for LinkedIn, X (Twitte
Automatically backs up your workflows to Github and generates documentation in a Notion database. Weekly run, uses the "internal-infra" tag to look for new or recently modified workflows Uses a Notion