{
  "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: `\ud83d\udea8 *${severity} TICKET* | ${email}\\n> \"${subject}\"\\n\ud83d\udcb0 ARR: $${revenue} (${stage})\\n\ud83d\udc49 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": "=\ud83d\udd25 *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
      ],
      "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
          }
        ]
      ]
    }
  }
}