This workflow corresponds to n8n.io template #15228 — 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": "mQeUGiy3jYf6liN5",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Customer 360 - Help Scout, HubSpot & SMS",
"tags": [],
"nodes": [
{
"id": "22e2a6c9-34ad-444a-b84d-0f09f40a04cc",
"name": "Sticky Note Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
320
],
"parameters": {
"color": 4,
"width": 608,
"height": 656,
"content": "## AI Customer 360 (Help Scout + HubSpot + SMS)\n\n### How it works\n1. Receives Help Scout events via webhook \n2. Extracts customer and ticket data \n3. Fetches HubSpot CRM data and recent SMS history \n4. Merges all data into a unified customer context \n5. Uses AI to generate a draft reply and perform QA (sentiment + approval) \n6. Routes the ticket:\n - Negative/Angry \u2192 Escalate to human \n - Approved + High value \u2192 Save draft \n - Others \u2192 Manual review \n\n---\n\n### Setup\n- Configure Help Scout webhook (POST \u2192 this workflow) \n- Add HubSpot API credentials \n- Add SMS API credentials \n- Add OpenAI API credentials \n\n**Required variables:**\n- `salesMessengerApiUrl` = SMS API endpoint \n- `highValueThreshold` = deal value threshold \n- `humanAgentId` = Help Scout user ID for escalation \n\n---\n\n### Customization\n- Adjust sentiment routing logic in the Switch node \n- Modify AI prompts for tone, brand voice, or constraints \n- Change approval rules (deal value threshold, QA conditions) \n- Extend data sources (e.g., add more CRM fields or channels) "
},
"typeVersion": 1
},
{
"id": "8ddf88ca-671b-40df-977c-2af423529d0d",
"name": "HelpScout Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
848,
672
],
"parameters": {
"path": "helpscout-context-sync",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 1
},
{
"id": "4b4d3c7a-b89c-497b-87ca-cad26f4d381d",
"name": "Parse Event",
"type": "n8n-nodes-base.code",
"position": [
1088,
672
],
"parameters": {
"jsCode": "// Catch HelpScout webhook and route based on X-HelpScout-Event header\nconst headers = $input.first().json.headers;\nconst body = $input.first().json.body;\nconst eventType = headers['x-helpscout-event'];\n\n// Only process new conversations or customer replies\nif (eventType === 'convo.created' || eventType === 'convo.customer.reply.created') {\n return [{ json: { eventType, payload: body } }];\n}\n\n// Ignore other events to save API calls\nreturn [];"
},
"typeVersion": 2
},
{
"id": "6f13325e-53ab-4fa0-93b2-0cf24d88aa71",
"name": "Extract Data",
"type": "n8n-nodes-base.code",
"position": [
1328,
672
],
"parameters": {
"jsCode": "// Extract core identifiers from HelpScout v2 payload\nconst payload = $json.payload;\nconst email = payload.primaryCustomer?.emails?.[0]?.value || payload.customer?.email;\nconst ticketId = payload.id;\nconst subject = payload.subject;\nconst preview = payload.preview;\n\nif (!email) return []; // Drop if no email\n\nreturn [{ json: { email, ticketId, subject, preview, source: 'helpscout' } }];"
},
"typeVersion": 2
},
{
"id": "122f7883-fe6e-4d08-a4e9-7d81b0ac618f",
"name": "Fetch HubSpot Context",
"type": "n8n-nodes-base.httpRequest",
"position": [
1568,
592
],
"parameters": {
"url": "https://api.hubapi.com/crm/v3/objects/contacts/search",
"method": "POST",
"options": {},
"jsonBody": "={\n \"filterGroups\": [\n {\n \"filters\": [\n {\n \"propertyName\": \"email\",\n \"operator\": \"EQ\",\n \"value\": \"{{ $json.email }}\"\n }\n ]\n }\n ],\n \"properties\": [\"dealstage\", \"account_tier\", \"onboarding_status\", \"associated_deal_amount\"]\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "hubSpotApi"
},
"typeVersion": 4.1
},
{
"id": "f982e35b-7ebe-4c3c-80df-77e916797532",
"name": "Fetch SMS History",
"type": "n8n-nodes-base.httpRequest",
"position": [
1568,
752
],
"parameters": {
"url": "={{ $vars.salesMessengerApiUrl }}?contact_email={{ $json.email }}&limit=5",
"options": {},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "salesMessengerApi"
},
"typeVersion": 4.1
},
{
"id": "b83dc7d3-3796-412a-ab01-6b651f126873",
"name": "Merge Context",
"type": "n8n-nodes-base.merge",
"position": [
1888,
672
],
"parameters": {
"mode": "combine",
"options": {},
"combinationMode": "mergeByPosition"
},
"typeVersion": 2
},
{
"id": "e1d2def8-77fa-4ec1-ab57-7caaeef10d19",
"name": "Build Shared Context Layer",
"type": "n8n-nodes-base.code",
"position": [
2048,
672
],
"parameters": {
"jsCode": "const hsData = $json[0]?.results?.[0] || {};\nconst smsData = $json[1]?.messages || [];\nconst inputData = $json[0]?.inputData || {};\n\nlet smsHistoryString = \"No recent SMS.\";\nif (smsData.length > 0) {\n smsHistoryString = smsData.map(m => `[${m.direction}] ${m.body}`).join(' | ');\n}\n\nconst sharedContext = `\n--- CUSTOMER 360 CONTEXT ---\n1. CURRENT TICKET (Help Scout): ID {{ $json[\"ticketId\"] }}, Subject: {{ $json[\"subject\"] }}, Preview: {{ $json[\"preview\"] }}\n2. HUBSPOT CRM: Deal Stage: ${hsData.dealstage || 'N/A'}, Account Tier: ${hsData.account_tier || 'Free'}, Onboarding Status: ${hsData.onboarding_status || 'N/A'}, Associated Deal Value: ${hsData.associated_deal_amount || 0}\n3. RECENT SMS ACTIVITY: ${smsHistoryString}\n---------------------------\n`;\n\nreturn [{ json: { \n sharedContext, \n email: inputData.email, \n ticketId: inputData.ticketId,\n accountTier: hsData.account_tier || 'Free',\n dealValue: Number(hsData.associated_deal_amount) || 0\n}}];"
},
"typeVersion": 2
},
{
"id": "56cfd2b6-b349-4f53-bbe0-614ab1a8ce61",
"name": "AI Draft Generator",
"type": "n8n-nodes-base.openAi",
"position": [
2384,
672
],
"parameters": {
"model": "gpt-4o",
"prompt": "You are an empathetic support agent for a K-12 SaaS. Using ONLY the provided context, draft a reply. Do not invent features.\n\n{{ $json.sharedContext }}\n\nDRAFTED REPLY:",
"options": {},
"requestOptions": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "e9d76a0a-e003-4bff-94ef-dccc9f306c76",
"name": "AI QA & Sentiment Check",
"type": "n8n-nodes-base.openAi",
"position": [
2560,
672
],
"parameters": {
"model": "gpt-4o-mini",
"prompt": "You are a QA auditor. Review this AI drafted response for a K-12 SaaS. Check for brand safety and empathy. \n\nRespond ONLY in JSON format:\n{ \"approved\": boolean, \"sentiment_score\": \"positive/neutral/negative/angry\", \"reason\": \"string\" }\n\nDRAFT TO EVALUATE:\n{{ $json.message.content }}",
"options": {},
"requestOptions": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "c30dc6f2-ee33-4b1d-ac3d-8f29820181b3",
"name": "Parse QA Output",
"type": "n8n-nodes-base.code",
"position": [
2864,
672
],
"parameters": {
"jsCode": "const qaResult = JSON.parse($json.message.content);\nconst draft = $('AI Draft Generator').item.json.message.content;\n\nreturn [{ \n json: {\n ...qaResult,\n draft,\n email: $('Build Shared Context Layer').item.json.email,\n ticketId: $('Build Shared Context Layer').item.json.ticketId,\n dealValue: $('Build Shared Context Layer').item.json.dealValue\n }\n}];"
},
"typeVersion": 2
},
{
"id": "cfe03de4-1069-4b00-af3a-5c06689e8369",
"name": "Sentiment Router",
"type": "n8n-nodes-base.switch",
"position": [
3008,
672
],
"parameters": {
"rules": {
"rules": [
{
"value2": "angry",
"outputKey": "Angry Sentiment"
},
{
"value2": "negative",
"outputKey": "Negative Sentiment"
}
]
},
"value1": "={{ $json.sentiment_score }}",
"dataType": "string",
"fallbackOutput": 1
},
"typeVersion": 2
},
{
"id": "84d3d39e-37fe-45cb-bd7a-427d7d2c93bf",
"name": "High Value + Approved?",
"type": "n8n-nodes-base.if",
"position": [
3248,
592
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "check_approved",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.approved }}"
},
{
"id": "check_value",
"operator": {
"type": "number",
"operation": "largerEqual"
},
"leftValue": "={{ $json.dealValue }}",
"rightValue": "={{ $vars.highValueThreshold }}"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "5b1f8c4c-9b72-46d7-a080-0b30b5de7dee",
"name": "Save Draft (Auto-Suggest)",
"type": "n8n-nodes-base.httpRequest",
"position": [
3488,
512
],
"parameters": {
"url": "https://api.helpscout.net/v2/conversations/{{ $json.ticketId }}/threads",
"method": "POST",
"options": {},
"jsonBody": "={\n \"type\": \"reply\",\n \"text\": \"{{ $json.draft }}\",\n \"draft\": true,\n \"createdBy\": { \"type\": \"bot\", \"id\": \"123\" }\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "helpScoutApi"
},
"typeVersion": 4.1
},
{
"id": "ee685206-ceec-4b8f-88c3-c38ab5f8bb56",
"name": "Escalate to Human",
"type": "n8n-nodes-base.httpRequest",
"position": [
3488,
752
],
"parameters": {
"url": "https://api.helpscout.net/v2/conversations/{{ $json.ticketId }}",
"method": "PATCH",
"options": {},
"jsonBody": "={\n \"assignedTo\": { \"type\": \"user\", \"id\": \"{{ $vars.humanAgentId }}\" },\n \"tags\": [\"ai-escalation\", \"{{ $json.sentiment_score }}\"]\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "helpScoutApi"
},
"typeVersion": 4.1
},
{
"id": "001504db-cc47-486f-8cda-466369782345",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3728,
592
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={ \"status\": \"processed_and_routed\" }"
},
"typeVersion": 1
},
{
"id": "89f1a66f-617d-40f9-a8bf-938b95a8071e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
816,
480
],
"parameters": {
"width": 384,
"height": 352,
"content": "## 1: Ingestion\n\n### Webhook Trigger and Parse\n\nReceives HelpScout events through a webhook and parses them for routing."
},
"typeVersion": 1
},
{
"id": "f4f51a94-1c2e-4209-81f9-891f09c3641b",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1328,
464
],
"parameters": {
"width": 416,
"height": 448,
"content": "## 2: Data Enrichment\n\n### Extract and Fetch Data\n\nExtracts identifiers and fetches HubSpot and SMS histories for context."
},
"typeVersion": 1
},
{
"id": "9f12902b-00f6-4cc4-a74b-4edd70ebcc47",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1840,
496
],
"parameters": {
"width": 352,
"height": 352,
"content": "## 3: Context Building\n\n### Merge and Build Context\n\nCombines fetched data and builds a shared context layer."
},
"typeVersion": 1
},
{
"id": "4ed9d98b-e872-4837-a47a-e1d7c52a0596",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2336,
480
],
"parameters": {
"width": 368,
"height": 384,
"content": "## 4: AI Processing\n\n### AI Processing and QA\n\nGenerates AI drafts and performs quality and sentiment checks.\n"
},
"typeVersion": 1
},
{
"id": "138122c9-6e67-4781-acc7-5e5ca091c30e",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2832,
320
],
"parameters": {
"width": 848,
"height": 640,
"content": "## Group 5: Routing & Action\n\n### Sentiment Routing and Action\n\nRoutes based on sentiment analysis and determines if escalation is needed."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "c8798a24-be0d-4891-93ab-acbefa901064",
"connections": {
"Parse Event": {
"main": [
[
{
"node": "Extract Data",
"type": "main",
"index": 0
}
]
]
},
"Extract Data": {
"main": [
[
{
"node": "Fetch HubSpot Context",
"type": "main",
"index": 0
},
{
"node": "Fetch SMS History",
"type": "main",
"index": 0
}
]
]
},
"Merge Context": {
"main": [
[
{
"node": "Build Shared Context Layer",
"type": "main",
"index": 0
}
]
]
},
"Parse QA Output": {
"main": [
[
{
"node": "Sentiment Router",
"type": "main",
"index": 0
}
]
]
},
"Sentiment Router": {
"main": [
[
{
"node": "Escalate to Human",
"type": "main",
"index": 0
}
],
[
{
"node": "High Value + Approved?",
"type": "main",
"index": 0
}
]
]
},
"Escalate to Human": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Fetch SMS History": {
"main": [
[
{
"node": "Merge Context",
"type": "main",
"index": 1
}
]
]
},
"HelpScout Webhook": {
"main": [
[
{
"node": "Parse Event",
"type": "main",
"index": 0
}
]
]
},
"AI Draft Generator": {
"main": [
[
{
"node": "AI QA & Sentiment Check",
"type": "main",
"index": 0
}
]
]
},
"Fetch HubSpot Context": {
"main": [
[
{
"node": "Merge Context",
"type": "main",
"index": 0
}
]
]
},
"High Value + Approved?": {
"main": [
[
{
"node": "Save Draft (Auto-Suggest)",
"type": "main",
"index": 0
}
],
[
{
"node": "Escalate to Human",
"type": "main",
"index": 0
}
]
]
},
"AI QA & Sentiment Check": {
"main": [
[
{
"node": "Parse QA Output",
"type": "main",
"index": 0
}
]
]
},
"Save Draft (Auto-Suggest)": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Build Shared Context Layer": {
"main": [
[
{
"node": "AI Draft Generator",
"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.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Categories Customer Support Automation, AI Agents, CRM Integration, SaaS Operations
Source: https://n8n.io/workflows/15228/ — 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 powerful n8n automation workflow is designed to execute advanced B2B lead enrichment and hyper-personalization for cold email outreach. By orchestrating a complex chain of data scraping, AI analy
Eu Clara – Funil Kiwify Completo. Uses postgres, openAi, httpRequest, gmail. Webhook trigger; 70 nodes.
This workflow bridges the gap between raw product data and revenue sales tools. It automates the entire Product Qualified Lead (PQL) lifecycle—from real-time intent routing to churn prevention—reducin
Lua Nova - Sistema Completo. Uses postgres, httpRequest, openAi. Webhook trigger; 55 nodes.
User Signup & Verification: The workflow starts when a user signs up. It generates a verification code and sends it via SMS using Twilio. Code Validation: The user replies with the code. The workflow