---
title: "Auto-Classify and Route Support Tickets with AI in n8n"
description: "Build an n8n workflow that uses AI to classify and route support tickets by category and priority. Step-by-step recipe with node configs and model tips."
canonical: https://agentroost.app/en/blog/ai-text-classification-support-tickets-n8n
date: 2026-05-15T12:00:00Z
---

[Canonical URL](https://agentroost.app/en/blog/ai-text-classification-support-tickets-n8n)

Manual ticket triage is a silent time-sink. Someone reads the message, decides whether it is a billing question, a bug report, or a pre-sales inquiry, pastes it into the right Slack channel, and moves on — then repeats that 40 more times before lunch. AI text classification in n8n replaces that loop with a three-second workflow.

This post is a concrete recipe. By the end you will have a working n8n workflow that reads an incoming message, asks an LLM to assign one label from a predefined list, and branches on the result. Bring your own labels — the same pattern works for support tickets, incoming leads, contact-form submissions, or app feedback.

---

## The classification recipe in one sentence

Feed the message to an LLM with a **closed list of labels** and a strict instruction to return exactly one. Branch on the value. Done.

The closed-list constraint is the whole trick. Without it the model invents labels ("it's kind of a billing issue but also a UX complaint"), which breaks branching. With it you get deterministic routing.

---

## Step 1 — Define your label taxonomy

Before touching n8n, write down your labels. Keep the list short and mutually exclusive. A good starting point for a SaaS support queue:

| Label | Covers |
|---|---|
| `billing` | Invoices, plan upgrades, refunds, payment failures |
| `bug` | Something broken, unexpected errors, feature not working |
| `feature-request` | "Can you add…" or "it would be great if…" |
| `onboarding` | Setup questions, first-run confusion |
| `general` | Everything that doesn't fit above |

If tickets also need a **priority** dimension, add a second pass (a second AI node, same pattern) rather than combining category + priority into one prompt — classification accuracy drops fast when you ask the model to decide two things at once.

---

## Step 2 — Build the trigger

The entry point depends on where tickets arrive:

- **Webhook node** — if tickets come from a custom form, Intercom, Front, or any platform that can POST to a URL. n8n gives you a public HTTPS webhook URL automatically; no reverse-proxy setup needed.
- **Email Trigger (IMAP) node** — if tickets arrive by email. Set `Poll Times` to every minute.
- **Schedule Trigger + HTTP Request** — if you are polling a helpdesk API (e.g., Freshdesk, Zendesk) on an interval.

For the rest of this walkthrough, assume a **Webhook** trigger receiving a JSON body like:

```json
{
  "ticket_id": "TK-4821",
  "from": "user@example.com",
  "subject": "Can't export my invoice",
  "body": "Hi, I upgraded to Pro yesterday and the invoice PDF download button does nothing."
}
```

---

## Step 3 — Build the AI Classifier node

Add an **AI Agent** node (or the **Basic LLM Chain** node if you want less overhead). Wire it to the Webhook output.

### System prompt

```
You are a support ticket classifier.

Classify the ticket below into EXACTLY ONE of these categories:
billing, bug, feature-request, onboarding, general

Rules:
- Return ONLY the category label, lowercase, no punctuation, no explanation.
- If unsure, return "general".
```

### User message (expression)

```
Subject: {{ $json.subject }}
Body: {{ $json.body }}
```

### Model choice

For a classification task at high volume, pick a **small, fast, cheap model** — you do not need frontier-class reasoning for label selection. Good options available on AgentRoost's included model roster:

- `google/gemini-flash-1.5` — very fast, long context, great at structured output
- `meta-llama/llama-3.1-8b-instruct` — open-weight, low latency, sufficient for short texts
- `anthropic/claude-3-haiku` — reliable at instruction following, good accuracy/cost ratio

Classification prompts are short and the cost per ticket is low even at high volumes — reserve your heavier credits for generation tasks like auto-drafting replies.

### Capture the output

The model will return a plain string like `billing`. Use a **Set node** immediately after to normalise it:

```json
{
  "category": "={{ $json.output.trim().toLowerCase() }}"
}
```

This guards against a stray newline or capitalisation inconsistency breaking your IF branches.

---

## Step 4 — Branch with a Switch node

Add a **Switch** node. Set the **Value** field to `{{ $json.category }}`. Create one output for each label:

- Output 0: `billing`
- Output 1: `bug`
- Output 2: `feature-request`
- Output 3: `onboarding`
- Output 4 (fallback): everything else → `general`

Each output wire connects to a different action: post to a Slack channel, create a Linear issue, assign to a specific inbox in your helpdesk, or fire a webhook to a separate system.

---

## Step 5 — Close the loop

For each branch, at minimum:

1. **Update the ticket** in your helpdesk (HTTP Request → PATCH the record with the label).
2. **Notify the right team** (Slack node, email, or a Telegram message).
3. **Log the classification** to a Google Sheet or a database via the Postgres node — after a week you'll have ground truth to spot where the model is getting it wrong.

A minimal Slack notification body looks like:

```
*[{{ $json.category | upper }}]* New ticket {{ $json.ticket_id }}
From: {{ $json.from }}
Subject: {{ $json.subject }}
```

---

## Tips and pitfalls

**Validate the label before branching.** If the LLM somehow returns an out-of-vocabulary string (it is rare with a strict prompt, but it happens), the Switch node's fallback output catches it. Wire the fallback to a `general` queue and an alert — do not let unclassified tickets silently disappear.

**Add an IF node for confidence gating (optional).** Ask the model to also return a `confidence` score (0–1) in a JSON object. If confidence is below 0.7, route to a human review queue instead of auto-routing. You'll need to swap from plain-text output to JSON output — update your prompt accordingly and parse with the **JSON Parse** node.

**Iterate on the taxonomy.** After reviewing logs for a week, you will almost always find a label that is too broad (bugs getting mixed with "it's slow" performance complaints) or a ghost label that never fires. Adjust the system prompt and labels without touching the branching logic.

**Test with the Webhook Test URL.** While building, use n8n's built-in "Listen for test event" mode and send a `curl` or a Postman request. No deployment needed.

---

## How to run this on AgentRoost

You own your n8n instance — it is not a shared service. Your login, your data, your workflows, your webhook URLs. AgentRoost gives you the infrastructure so you skip the DevOps.

1. [Sign up at agentroost.app](/en/pricing) — takes about 60 seconds with email, Google, Microsoft, or Discord.
2. Pick the **n8n framework**, give your instance a name.
3. Your private n8n editor opens at `https://<your-id>.agentroost.app`. No Docker, no SSL cert wrangling.
4. Build the workflow above. When you reach the AI node and choose a model, **no API key is required** — your subscription includes LLM credits. The AI nodes work immediately.
5. Activate the workflow and send a test ticket to your webhook URL.

Plans start at **$19.99/mo all-in** (compute + included AI credits). If it is not for you, the 14-day money-back guarantee is there. [Compare plans](/en/pricing) or go straight to the [n8n agent page](/en/agents/n8n) to see what's included.

---

## Going further

Once basic classification is working, two natural extensions:

- **Sentiment overlay** — a second AI node that flags frustrated-sounding tickets as `high-priority` regardless of category. Route those straight to a human.
- **Auto-draft reply** — after classification, pass the ticket body to a heavier model to generate a draft response. Staff still sends it, but composing from a draft cuts handle time significantly.

Both follow the same pattern: one AI node, a clear prompt, a structured output, then branch or act. The workflow gets longer but not fundamentally more complex.
