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 →
{
"name": "Revenue Ops CRM Sync and Enrichment",
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "03e50be0-bd1f-4444-8912-a426aa3efb76",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"id": "six_hour_trigger",
"name": "6 Hour Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
220,
320
]
},
{
"parameters": {
"resource": "deal",
"operation": "search",
"additionalFields": {}
},
"id": "hubspot_search_deals",
"name": "HubSpot Search Deals",
"type": "n8n-nodes-base.hubspot",
"typeVersion": 2.2,
"position": [
470,
320
]
},
{
"parameters": {
"jsCode": "return $input.all().map((item) => {\n const daysInStage = Number(item.json.daysInStage || item.json.stageAgeDays || 18);\n const amount = Number(item.json.amount || item.json.dealValue || 12000);\n\n let deterministicScore = 30;\n if (daysInStage > 14) deterministicScore += 25;\n if (daysInStage > 30) deterministicScore += 20;\n if (amount >= 10000) deterministicScore += 15;\n\n return {\n json: {\n ...item.json,\n deterministicScore,\n daysInStage,\n amount,\n },\n };\n});"
},
"id": "deterministic_deal_risk",
"name": "Deterministic Deal Risk",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
700,
320
]
},
{
"parameters": {
"promptType": "define",
"text": "={{'You assess revenue pipeline slippage. Return strict JSON with keys aiScore (0-100), priority (at_risk|healthy), summary (string). Deal payload: ' + JSON.stringify($json)}}",
"options": {}
},
"id": "ai_deal_risk_agent",
"name": "AI Deal Risk Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
940,
220
]
},
{
"parameters": {
"model": {
"mode": "list",
"value": "gpt-4.1-mini"
},
"options": {}
},
"id": "openai_chat_model",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.3,
"position": [
940,
520
]
},
{
"parameters": {
"jsCode": "return $input.all().map((item) => {\n const rawCandidate =\n item.json.output ??\n item.json.text ??\n item.json.response ??\n item.json.result ??\n item.json;\n\n let parsed = {};\n\n if (typeof rawCandidate === 'string') {\n try {\n parsed = JSON.parse(rawCandidate);\n } catch (error) {\n parsed = { summary: rawCandidate };\n }\n } else if (rawCandidate && typeof rawCandidate === 'object') {\n parsed = rawCandidate;\n }\n\n const pickNumber = (...keys) => {\n for (const key of keys) {\n const value = Number(parsed[key]);\n if (Number.isFinite(value) && value > 0) return value;\n }\n return 0;\n };\n\n const pickString = (...keys) => {\n for (const key of keys) {\n const value = parsed[key];\n if (typeof value === 'string' && value.trim()) return value.trim();\n }\n return '';\n };\n\n return {\n json: {\n aiScore: pickNumber('aiScore', 'score', 'riskScore', 'severityScore', 'readinessScore'),\n aiPriority: pickString('priority', 'queue', 'recommendation', 'decision'),\n aiSummary: pickString('summary', 'rationale', 'reason', 'triageSummary', 'recommendation') || 'ai_response_unavailable',\n aiPayload: parsed,\n },\n };\n});"
},
"id": "parse_ai_output",
"name": "Parse AI Output",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1160,
220
]
},
{
"parameters": {
"mode": "combine"
},
"id": "merge_ai_with_rules",
"name": "Merge AI with Rules",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1160,
360
]
},
{
"parameters": {
"jsCode": "return $input.all().map((item) => {\n const deterministicScore = Number(item.json.deterministicScore || 0);\n const aiScore = Number(item.json.aiScore || 0);\n const dealRiskScore = aiScore > 0\n ? Math.round((deterministicScore * 0.65) + (aiScore * 0.35))\n : deterministicScore;\n\n const health = dealRiskScore >= 70 ? 'at_risk' : 'healthy';\n\n return {\n json: {\n ...item.json,\n dealRiskScore,\n health,\n riskSummary: item.json.aiSummary || 'deterministic fallback used',\n },\n };\n});"
},
"id": "final_deal_decision",
"name": "Final Deal Decision",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1380,
360
]
},
{
"parameters": {
"resource": "contact",
"operation": "upsert",
"email": "={{\"owner@example.com\"}}",
"additionalFields": {}
},
"id": "hubspot_sync_owner_contact",
"name": "HubSpot Sync Owner Contact",
"type": "n8n-nodes-base.hubspot",
"typeVersion": 2.2,
"position": [
1600,
480
]
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{$json.dealRiskScore}}",
"operation": "largerEqual",
"value2": 70
}
]
}
},
"id": "at_risk_check",
"name": "At Risk Deal?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1600,
320
]
},
{
"parameters": {
"resource": "databasePage",
"operation": "create",
"databaseId": {
"mode": "url",
"value": "https://www.notion.so/00000000000000000000000000000000"
},
"title": "={{\"RevOps: \" + ($json.health || \"healthy\") + \" | score \" + ($json.dealRiskScore || 0)}}",
"simple": true
},
"id": "notion_revops_log",
"name": "Notion RevOps Log",
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
1820,
360
]
},
{
"parameters": {
"resource": "message",
"operation": "post",
"select": "channel",
"channelId": {
"mode": "id",
"value": "C01234567"
},
"messageType": "text",
"text": "={{\"\ud83d\udea8 At-risk deal detected | score \" + ($json.dealRiskScore || 0) + \" | days \" + ($json.daysInStage || 0)}}"
},
"id": "slack_at_risk_alert",
"name": "Slack At Risk Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.4,
"position": [
1820,
180
]
},
{
"parameters": {
"resource": "message",
"operation": "post",
"select": "channel",
"channelId": {
"mode": "id",
"value": "C01234567"
},
"messageType": "text",
"text": "={{\"\u2705 Deal health normal | score \" + ($json.dealRiskScore || 0)}}"
},
"id": "slack_healthy_update",
"name": "Slack Healthy Update",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.4,
"position": [
1820,
540
]
},
{
"parameters": {
"resource": "message",
"operation": "send",
"sendTo": "={{\"owner@example.com\"}}",
"subject": "RevOps Deal Health Summary",
"message": "={{\"Health: \" + ($json.health || \"healthy\") + \"\\nScore: \" + ($json.dealRiskScore || 0) + \"\\nSummary: \" + ($json.riskSummary || \"N/A\")}}"
},
"id": "gmail_revops_summary",
"name": "Gmail RevOps Summary",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
2050,
360
]
}
],
"connections": {
"6 Hour Trigger": {
"main": [
[
{
"node": "HubSpot Search Deals",
"type": "main",
"index": 0
}
]
]
},
"HubSpot Search Deals": {
"main": [
[
{
"node": "Deterministic Deal Risk",
"type": "main",
"index": 0
}
]
]
},
"Deterministic Deal Risk": {
"main": [
[
{
"node": "AI Deal Risk Agent",
"type": "main",
"index": 0
}
],
[
{
"node": "Merge AI with Rules",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Deal Risk Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Deal Risk Agent": {
"main": [
[
{
"node": "Parse AI Output",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Output": {
"main": [
[
{
"node": "Merge AI with Rules",
"type": "main",
"index": 1
}
]
]
},
"Merge AI with Rules": {
"main": [
[
{
"node": "Final Deal Decision",
"type": "main",
"index": 0
}
]
]
},
"Final Deal Decision": {
"main": [
[
{
"node": "At Risk Deal?",
"type": "main",
"index": 0
},
{
"node": "HubSpot Sync Owner Contact",
"type": "main",
"index": 0
}
]
]
},
"At Risk Deal?": {
"main": [
[
{
"node": "Slack At Risk Alert",
"type": "main",
"index": 0
},
{
"node": "Notion RevOps Log",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack Healthy Update",
"type": "main",
"index": 0
},
{
"node": "Notion RevOps Log",
"type": "main",
"index": 0
}
]
]
},
"Notion RevOps Log": {
"main": [
[
{
"node": "Gmail RevOps Summary",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Revenue Ops CRM Sync and Enrichment. Uses hubspot, agent, lmChatOpenAi, notion. Scheduled trigger; 14 nodes.
Source: https://github.com/JefferyAddaeSecB/n8n-revenue-ops-crm-sync/blob/d5353d2bd59cb3f8fe0bd376f5f580f6e6246104/n8n/workflow.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.
This workflow is designed for Customer Success Managers and Sales Teams who manage high-volume pipelines in HubSpot. If you have prospects who stop responding after the contract is sent, this automati
This workflow helps sales teams automatically monitor deal health and detect risks early.
This n8n template demonstrates how to use AI to triage LinkedIn emails in your Gmail inbox, so you only see the messages worth your time. It filters out automated noise, scores sales likelihood, draft
Created by: Peyton Leveillee Last updated: October 2025
This workflow automates customer outreach for marketing campaigns, including customer prioritization, AI-generated emails, automated sending, reply tracking, and meeting scheduling. Data Synchronizati