{
  "name": "AI Support Triage Bot — Classify, Auto-Reply or Escalate",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "support-ticket",
        "options": {}
      },
      "id": "d1e2f3a4-1111-4d2e-8f3a-0b1c2d3e4f5a",
      "name": "Webhook: New Ticket",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [-240, 300],
      "webhookId": "d1e2f3a4-1111-4d2e-8f3a-0b1c2d3e4f5a"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4o-mini",
          "mode": "list",
          "cachedResultName": "gpt-4o-mini"
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a support ticket triage system for a SaaS product. Classify each ticket.\n\nDefinitions:\n- urgency: \"low\" (question, feature request), \"medium\" (something broken with workaround), \"high\" (blocked, data loss, security, billing dispute, angry customer)\n- category: one of \"billing\", \"bug\", \"how_to\", \"account_access\", \"feature_request\", \"other\"\n- can_auto_answer: true ONLY if the ticket is a common how-to or billing question that can be answered from documentation without account-specific data.\n- confidence: 0.0-1.0, your confidence in the classification.\n- suggested_reply: if can_auto_answer is true, write a complete, friendly reply (2-4 short paragraphs, sign off as 'The Support Team'). Otherwise null.\n\nRespond ONLY with valid JSON, no markdown fences, exactly this shape:\n{\"urgency\": string, \"category\": string, \"can_auto_answer\": boolean, \"confidence\": number, \"suggested_reply\": string|null}"
            },
            {
              "role": "user",
              "content": "=Classify this support ticket:\nSubject: {{ $json.body.subject }}\nFrom: {{ $json.body.email }}\nMessage:\n{{ $json.body.message }}"
            }
          ]
        },
        "jsonOutput": true,
        "options": {
          "temperature": 0.1
        }
      },
      "id": "e2f3a4b5-2222-4e3f-9a4b-1c2d3e4f5a6b",
      "name": "OpenAI: Classify Ticket",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.8,
      "position": [0, 300],
      "credentials": {
        "openAiApi": {
          "id": "YOUR_OPENAI_CREDENTIAL",
          "name": "YOUR_OPENAI_CREDENTIAL"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Decide the route: auto_reply, escalate, or log\nconst ai = $input.first().json.message?.content ?? $input.first().json;\nconst ticket = $('Webhook: New Ticket').first().json.body;\n\nlet route = 'log';\nif (ai.urgency === 'high' || ai.confidence < 0.6) {\n  route = 'escalate';\n} else if (ai.can_auto_answer === true && ai.confidence >= 0.8 && ai.suggested_reply) {\n  route = 'auto_reply';\n}\n\nreturn [{\n  json: {\n    route,\n    ticket_id: ticket.ticket_id,\n    subject: ticket.subject,\n    email: ticket.email,\n    message: ticket.message,\n    urgency: ai.urgency,\n    category: ai.category,\n    confidence: ai.confidence,\n    suggested_reply: ai.suggested_reply,\n    triaged_at: new Date().toISOString(),\n  },\n}];"
      },
      "id": "f3a4b5c6-3333-4f4a-8b5c-2d3e4f5a6b7c",
      "name": "Code: Pick Route",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [240, 300]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "a4b5c6d7-4441-4a5b-9c6d-3e4f5a6b7c8d",
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "auto_reply",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Auto Reply"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "a4b5c6d7-4442-4a5b-9c6d-3e4f5a6b7c8e",
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "escalate",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Escalate"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "a4b5c6d7-4443-4a5b-9c6d-3e4f5a6b7c8f",
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "log",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Log"
            }
          ]
        },
        "options": {}
      },
      "id": "a4b5c6d7-4444-4a5b-9c6d-3e4f5a6b7c80",
      "name": "Switch: Route Ticket",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [480, 300]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://yourhelpdesk.example.com/api/v2/tickets/{{ $json.ticket_id }}/reply",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ body: $json.suggested_reply, status: 'pending', tags: ['ai-auto-reply', $json.category] }) }}",
        "options": {}
      },
      "id": "b5c6d7e8-5555-4b6c-8d7e-4f5a6b7c8d9e",
      "name": "Helpdesk: Send Auto-Reply",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [740, 120],
      "credentials": {
        "httpHeaderAuth": {
          "id": "YOUR_HELPDESK_CREDENTIAL",
          "name": "YOUR_HELPDESK_CREDENTIAL"
        }
      }
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#support-escalations",
          "mode": "name"
        },
        "text": "=:rotating_light: *Escalated ticket #{{ $json.ticket_id }}* ({{ $json.urgency }} / {{ $json.category }})\nFrom: {{ $json.email }}\nSubject: {{ $json.subject }}\nConfidence: {{ $json.confidence }}\n> {{ $json.message.slice(0, 400) }}",
        "otherOptions": {}
      },
      "id": "c6d7e8f9-6666-4c7d-9e8f-5a6b7c8d9e0f",
      "name": "Slack: Escalate",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [740, 300],
      "credentials": {
        "slackApi": {
          "id": "YOUR_SLACK_CREDENTIAL",
          "name": "YOUR_SLACK_CREDENTIAL"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Triage Log",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Date": "={{ $json.triaged_at }}",
            "Ticket ID": "={{ $json.ticket_id }}",
            "Email": "={{ $json.email }}",
            "Subject": "={{ $json.subject }}",
            "Urgency": "={{ $json.urgency }}",
            "Category": "={{ $json.category }}",
            "Confidence": "={{ $json.confidence }}"
          }
        },
        "options": {}
      },
      "id": "d7e8f9a0-7777-4d8e-8f9a-6b7c8d9e0f1a",
      "name": "Google Sheets: Log Ticket",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [740, 480],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "YOUR_GOOGLE_SHEETS_CREDENTIAL",
          "name": "YOUR_GOOGLE_SHEETS_CREDENTIAL"
        }
      }
    }
  ],
  "connections": {
    "Webhook: New Ticket": {
      "main": [
        [
          {
            "node": "OpenAI: Classify Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI: Classify Ticket": {
      "main": [
        [
          {
            "node": "Code: Pick Route",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Pick Route": {
      "main": [
        [
          {
            "node": "Switch: Route Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch: Route Ticket": {
      "main": [
        [
          {
            "node": "Helpdesk: Send Auto-Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack: Escalate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Sheets: Log Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
