{
  "name": "AI Support Ticket Triage",
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "901ed2f2-7d68-4ff0-ab85-e3885f97607c",
  "nodes": [
    {
      "parameters": {
        "path": "support-ticket-v3",
        "httpMethod": "POST",
        "responseMode": "onReceived"
      },
      "id": "ticket_webhook",
      "name": "Ticket Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        220,
        320
      ]
    },
    {
      "parameters": {
        "jsCode": "return $input.all().map((item) => {\n  const subject = String(item.json.subject || 'No subject');\n  const message = String(item.json.message || item.json.description || 'No message');\n  return {\n    json: {\n      ...item.json,\n      subject,\n      message,\n      receivedAt: new Date().toISOString(),\n    },\n  };\n});"
      },
      "id": "normalize_ticket",
      "name": "Normalize Ticket",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        450,
        320
      ]
    },
    {
      "parameters": {
        "jsCode": "return $input.all().map((item) => {\n  const lowered = (String(item.json.subject || '') + ' ' + String(item.json.message || '')).toLowerCase();\n\n  let deterministicScore = 30;\n  if (lowered.includes('outage') || lowered.includes('down')) deterministicScore += 35;\n  if (lowered.includes('payment') || lowered.includes('billing')) deterministicScore += 20;\n  if (lowered.includes('security') || lowered.includes('breach')) deterministicScore += 25;\n\n  return {\n    json: {\n      ...item.json,\n      deterministicScore,\n      baselineQueue: deterministicScore >= 70 ? 'urgent-human' : 'ai-assisted',\n    },\n  };\n});"
      },
      "id": "deterministic_ticket_score",
      "name": "Deterministic Ticket Score",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        320
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{'You triage support tickets. Return strict JSON with keys aiScore (0-100), priority (urgent-human|human|ai-assisted), summary (string). Ticket payload: ' + JSON.stringify($json)}}",
        "options": {}
      },
      "id": "ai_ticket_triage_agent",
      "name": "AI Ticket Triage 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 triageScore = aiScore > 0\n    ? Math.round((deterministicScore * 0.6) + (aiScore * 0.4))\n    : deterministicScore;\n\n  const queue = triageScore >= 70\n    ? 'urgent-human'\n    : (item.json.aiPriority || item.json.baselineQueue || 'ai-assisted');\n\n  return {\n    json: {\n      ...item.json,\n      triageScore,\n      queue,\n      summary: item.json.aiSummary || 'deterministic fallback used',\n    },\n  };\n});"
      },
      "id": "final_ticket_decision",
      "name": "Final Ticket Decision",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1380,
        360
      ]
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{$json.triageScore}}",
              "operation": "largerEqual",
              "value2": 70
            }
          ]
        }
      },
      "id": "human_escalation_check",
      "name": "Human Escalation?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1600,
        360
      ]
    },
    {
      "parameters": {
        "resource": "databasePage",
        "operation": "create",
        "databaseId": {
          "mode": "url",
          "value": "https://www.notion.so/00000000000000000000000000000000"
        },
        "title": "={{\"Ticket: \" + ($json.subject || \"No subject\") + \" | \" + ($json.queue || \"ai-assisted\")}}",
        "simple": true
      },
      "id": "notion_log_ticket",
      "name": "Notion Log Ticket",
      "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 Urgent ticket: \" + ($json.subject || \"No subject\") + \" | score \" + ($json.triageScore || 0)}}"
      },
      "id": "slack_urgent_ticket",
      "name": "Slack Urgent Ticket",
      "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": "={{\"Ticket triaged to \" + ($json.queue || \"ai-assisted\") + \" | \" + ($json.subject || \"No subject\")}}"
      },
      "id": "slack_standard_ticket",
      "name": "Slack Standard Ticket",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.4,
      "position": [
        1820,
        540
      ]
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "send",
        "sendTo": "={{$json.email || \"customer@example.com\"}}",
        "subject": "Support Ticket Update",
        "message": "={{\"Queue: \" + ($json.queue || \"ai-assisted\") + \"\\nSummary: \" + ($json.summary || \"pending\")}}"
      },
      "id": "gmail_ticket_update",
      "name": "Gmail Ticket Update",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.2,
      "position": [
        2050,
        360
      ]
    }
  ],
  "connections": {
    "Ticket Webhook": {
      "main": [
        [
          {
            "node": "Normalize Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Ticket": {
      "main": [
        [
          {
            "node": "Deterministic Ticket Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Deterministic Ticket Score": {
      "main": [
        [
          {
            "node": "AI Ticket Triage Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge AI with Rules",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Ticket Triage Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "AI Ticket Triage 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 Ticket Decision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Final Ticket Decision": {
      "main": [
        [
          {
            "node": "Human Escalation?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Human Escalation?": {
      "main": [
        [
          {
            "node": "Slack Urgent Ticket",
            "type": "main",
            "index": 0
          },
          {
            "node": "Notion Log Ticket",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack Standard Ticket",
            "type": "main",
            "index": 0
          },
          {
            "node": "Notion Log Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notion Log Ticket": {
      "main": [
        [
          {
            "node": "Gmail Ticket Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}