{"nodes":[{"id":"eab71572-72da-4bf2-9143-ea6895eb822f","name":"Every 10 Mins","type":"n8n-nodes-base.scheduleTrigger","position":[-464,160],"parameters":{"rule":{"interval":[{"field":"minutes","minutesInterval":10}]}},"typeVersion":1.3},{"id":"63faef9b-c7fe-40b9-b937-7df97f1b4d08","name":"HubSpot: Search New Tickets","type":"n8n-nodes-base.httpRequest","position":[-240,160],"parameters":{"url":"https://api.hubapi.com/crm/v3/objects/tickets/search","method":"POST","options":{},"jsonBody":"={\n  \"filterGroups\": [\n    {\n      \"filters\": [\n        {\n          \"propertyName\": \"createdate\",\n          \"operator\": \"GTE\",\n          \"value\": \"{{ $now.minus({minutes: 10}).toMillis() }}\"\n        }\n      ]\n    }\n  ],\n  \"sorts\": [\n    {\n      \"propertyName\": \"createdate\",\n      \"direction\": \"DESCENDING\"\n    }\n  ],\n  \"properties\": [\n    \"subject\",\n    \"content\",\n    \"hs_ticket_category\",\n    \"hs_pipeline_stage\"\n  ]\n}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"hubspotAppToken"},"typeVersion":4.3},{"id":"21b22741-9688-4f07-a985-984892439465","name":"Check: Are there tickets?","type":"n8n-nodes-base.if","position":[-16,160],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"fca24971-8946-4409-8787-bbcb8fb2d6c8","operator":{"type":"number","operation":"gt"},"leftValue":"={{ $json.total }}","rightValue":0}]}},"typeVersion":2.3},{"id":"760efc8a-bbf5-4e85-8889-bd52a36b2dca","name":"Loop: Process Tickets","type":"n8n-nodes-base.splitOut","position":[208,160],"parameters":{"options":{},"fieldToSplitOut":"results"},"typeVersion":1},{"id":"48f84fac-65a4-4d54-bc07-7b564ca0cb5f","name":"HubSpot: Get Associations","type":"n8n-nodes-base.hubspot","position":[432,160],"parameters":{"resource":"ticket","ticketId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"operation":"get","authentication":"oAuth2","additionalFields":{"properties":["hs_all_associated_contact_emails"]}},"typeVersion":2.2},{"id":"35946b7b-3ed6-45b9-9334-576d05683f70","name":"Filter: Has Email?","type":"n8n-nodes-base.filter","position":[656,160],"parameters":{"options":{},"conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2d95cc52-8052-4a12-97e5-e16148c8d344","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.properties.hs_all_associated_contact_emails.versions[0].value }}","rightValue":""}]}},"typeVersion":2.3},{"id":"7e267a4b-dc0c-4b56-866b-1726bfdf6ff0","name":"HubSpot: Get Contact Data","type":"n8n-nodes-base.httpRequest","position":[880,160],"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.properties.hs_all_associated_contact_emails.value || $json.properties.hs_all_associated_contact_emails.versions[0].value).split(';')[0] }}\"\n        }\n      ]\n    }\n  ],\n  \"properties\": [\n    \"annualrevenue\",\n    \"lifecyclestage\",\n    \"company\"\n  ]\n}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"hubspotAppToken"},"typeVersion":4.3},{"id":"01ea5b8b-3308-4dba-bd0c-034f4fefdb41","name":"Code: Calculate Severity","type":"n8n-nodes-base.code","position":[1104,160],"parameters":{"jsCode":"// --- Input Handling ---\n// Retrieve Contact data (from current input) and Ticket data (from lookup node)\nconst contactResponse = $input.item.json;\n// Handle HubSpot API variations: 'results' array (Search API) vs direct object (Get API)\nconst contactProps = contactResponse.results ? contactResponse.results[0].properties : contactResponse.properties;\n\nconst ticketNode = $('HubSpot: Get Associations').item.json;\nconst ticketProps = ticketNode.properties;\n\n// --- Property Extraction ---\nconst revenue = parseFloat(contactProps.annualrevenue || 0);\nconst stage = contactProps.lifecyclestage || \"unknown\";\n\nconst email = contactProps.email;\nconst subject = ticketProps.subject || \"No Subject\";\nconst message = ticketProps.content || \"\";\n\n// --- Logic Thresholds ---\nconst isHighRevenue = revenue > 10000;\nconst isEnterprise = stage === 'evangelist' || stage === 'customer';\n\n// Check for churn risk keywords in ticket content\nconst criticalKeywords = [\"cancel\", \"refund\", \"expensive\", \"lawyer\", \"competitor\", \"broken\"];\nconst isChurnRisk = criticalKeywords.some(keyword => message.toLowerCase().includes(keyword));\n\nlet severity = \"Normal\";\nlet owner = \"support-general\";\n\n// --- Triage Logic ---\nif (isHighRevenue && isChurnRisk) {\n  severity = \"CRITICAL\";\n  owner = \"head-of-cs\";\n} else if (isHighRevenue) {\n  severity = \"High\";\n  owner = \"senior-csm\";\n} else if (isChurnRisk) {\n  severity = \"High\";\n  owner = \"retention-team\";\n}\n\n// --- Output Payload ---\nreturn {\n  json: {\n    subject: subject,\n    customer_email: email,\n    hubspot_revenue: revenue,\n    hubspot_stage: stage,\n    severity: severity,\n    assigned_to: owner,\n    timestamp: new Date().toISOString(),\n    slack_message: `🚨 *${severity} TICKET* | ${email}\\n> \"${subject}\"\\n💰 ARR: $${revenue} (${stage})\\n👉 Assignee: @${owner}`,\n    jira_summary: `[${severity}] ${email} - ${subject}`\n  }\n};"},"typeVersion":1},{"id":"b51655fe-d7b9-4740-9cc5-0cc93674a9c7","name":"Jira: Create Triage Ticket","type":"n8n-nodes-base.jira","position":[1328,160],"parameters":{"project":{"__rl":true,"mode":"list"},"summary":"={{ $json.jira_summary }}","issueType":{"__rl":true,"mode":"list"},"additionalFields":{"description":"=h3. Issue Details\n*Customer:* {{ $('Filter: Has Email?').item.json.properties.hs_all_associated_contact_emails.value }}\n*Revenue:* ${{ $json.hubspot_revenue }} ({{ $json.hubspot_stage }})\n*Assignee:* {{ $json.assigned_to }}\nh3. Severity Analysis \n*Level:* {{ $json.severity }}\n*Risk Factor:* {{ $json.severity === 'CRITICAL' ? 'High Value + Churn Risk' : 'Standard Ticket' }}"}},"typeVersion":1},{"id":"ee9b8dd8-1794-4655-94af-613e42da7e68","name":"Slack: Notify Channel","type":"n8n-nodes-base.slack","position":[1552,160],"parameters":{"text":"={{ $('Code: Calculate Severity').item.json.slack_message }}","channel":"customer-success","attachments":[],"otherOptions":{}},"typeVersion":1},{"id":"ef436359-a48d-4370-82fb-f5b24615a2d6","name":"Jira: Get Latest Status","type":"n8n-nodes-base.jira","position":[2000,160],"parameters":{"issueKey":"={{ $('Jira: Create Triage Ticket').item.json.key }}","operation":"get","additionalFields":{}},"typeVersion":1},{"id":"9e96bcba-7132-40d0-8485-5d2354867633","name":"Check: Escalation Needed?","type":"n8n-nodes-base.if","position":[2224,160],"parameters":{"conditions":{"string":[{"value1":"={{ $json.fields.status.name }}","value2":"Done","operation":"notEqual"},{"value1":"={{ $json.fields.status.name }}","value2":"In Progress","operation":"notEqual"}]}},"typeVersion":1},{"id":"f08cf9f8-e880-4e99-9635-3e186f5b9a37","name":"Slack: Send Alert","type":"n8n-nodes-base.slack","position":[2448,160],"parameters":{"text":"=🔥 *CHURN RISK ESCALATION*: VIP Ticket {{ $json.key }} untouched for 15 mins. @channel","channel":"customer-success","attachments":[],"otherOptions":{}},"typeVersion":1},{"id":"b1708a4c-e8aa-4a5b-bb60-a471b0333cc2","name":"Wait: Response Timer","type":"n8n-nodes-base.wait","position":[1776,160],"webhookId":"ac82759e-4d23-45a8-b649-16584982635d","parameters":{"unit":"minutes","amount":15},"typeVersion":1},{"id":"8f1d52b6-b4b8-4f52-8e8c-5b304cdb79af","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-496,-112],"parameters":{"color":7,"width":624,"height":464,"content":"## Workflow Setup & Trigger\n\n* **Schedule:** Runs every 10 minutes to check for new tickets.\n* **HubSpot Search:** Retrieves only tickets created within the last 10 minutes to prevent duplicates.\n* **Validation:** Checks if any tickets were found; stops execution immediately if the result is empty."},"typeVersion":1},{"id":"1ff838d0-7195-4fb3-8fcd-a2789ea57303","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[160,-112],"parameters":{"color":7,"width":864,"height":464,"content":"## Data Enrichment\n\n* **Loop:** Splits the batch of tickets to process them one by one.\n* **Associations:** Queries HubSpot to find the Contact associated with the Ticket.\n* **Contact Details:** Retrieves critical business data (Annual Revenue, Lifecycle Stage) to identify VIP customers."},"typeVersion":1},{"id":"28561074-d2b8-47bb-81cf-d058272ef7aa","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1056,-112],"parameters":{"color":7,"width":640,"height":464,"content":"## Logic & Triage\n\n* **Severity Calculation:** Uses JavaScript to classify tickets as CRITICAL, High, or Normal based on revenue thresholds and churn risk keywords.\n* **Jira Task:** Creates a new task in the specific project with a formatted description containing all customer context.\n* **Notification:** Sends an immediate alert to the Customer Success Slack channel."},"typeVersion":1},{"id":"d14a3c50-7445-4f0a-b2ef-dd29475a8fa1","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1728,-112],"parameters":{"color":7,"width":848,"height":464,"content":"## SLA Monitor & Escalation\n\n* **Wait Timer:** Pauses the workflow for 15 minutes (SLA buffer).\n* **Status Check:** Queries Jira to see if the ticket is still in 'To Do' status.\n* **Escalation:** If the ticket remains untouched, sends a high-priority alert to the team."},"typeVersion":1},{"id":"8fd8f1de-5974-48ae-bac9-97e8442892e0","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-400,-560],"parameters":{"width":640,"height":304,"content":"## Workflow Overview\n\n**Automated VIP Ticket Escalation**\n\nThis workflow acts as an automated triage system to ensure high-value customers receive immediate attention.\n\n* **Trigger:** Monitors HubSpot for new tickets every 10 minutes.\n* **Triage:** Enriches ticket data with Contact revenue and uses code to calculate severity (Critical/High/Normal).\n* **Sync:** Automatically creates a detailed Jira task for the engineering/support team.\n* **SLA Check:** Waits 15 minutes and checks the Jira status. If the ticket is still untouched, it triggers an escalation alert in Slack."},"typeVersion":1},{"id":"77bada53-dd71-4517-b6f8-f8d3eb1b3c33","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-416,480],"parameters":{"color":6,"width":368,"height":212,"content":"## Contact me\n- If you need any modification to this workflow\n- if you need some help with this workflow\n- Or if you need any workflow in n8n, Make, or Langchain / Langgraph\n\nWrite to me: [thomas@pollup.net](mailto:thomas@pollup.net)\n\n**Take a look at my others workflows [here](https://n8n.io/creators/zeerobug/)**\n\n"},"typeVersion":1}],"connections":{"Every 10 Mins":{"main":[[{"node":"HubSpot: Search New Tickets","type":"main","index":0}]]},"Filter: Has Email?":{"main":[[{"node":"HubSpot: Get Contact Data","type":"main","index":0}]]},"Wait: Response Timer":{"main":[[{"node":"Jira: Get Latest Status","type":"main","index":0}]]},"Loop: Process Tickets":{"main":[[{"node":"HubSpot: Get Associations","type":"main","index":0}]]},"Slack: Notify Channel":{"main":[[{"node":"Wait: Response Timer","type":"main","index":0}]]},"Jira: Get Latest Status":{"main":[[{"node":"Check: Escalation Needed?","type":"main","index":0}]]},"Code: Calculate Severity":{"main":[[{"node":"Jira: Create Triage Ticket","type":"main","index":0}]]},"Check: Are there tickets?":{"main":[[{"node":"Loop: Process Tickets","type":"main","index":0}]]},"Check: Escalation Needed?":{"main":[[{"node":"Slack: Send Alert","type":"main","index":0}]]},"HubSpot: Get Associations":{"main":[[{"node":"Filter: Has Email?","type":"main","index":0}]]},"HubSpot: Get Contact Data":{"main":[[{"node":"Code: Calculate Severity","type":"main","index":0}]]},"Jira: Create Triage Ticket":{"main":[[{"node":"Slack: Notify Channel","type":"main","index":0}]]},"HubSpot: Search New Tickets":{"main":[[{"node":"Check: Are there tickets?","type":"main","index":0}]]}}}