Auto-Classify and Route Support Tickets with AI in 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 Timesto 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:
{
"ticket_id": "TK-4821",
"from": "[email protected]",
"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 outputmeta-llama/llama-3.1-8b-instruct— open-weight, low latency, sufficient for short textsanthropic/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:
{
"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:
- Update the ticket in your helpdesk (HTTP Request → PATCH the record with the label).
- Notify the right team (Slack node, email, or a Telegram message).
- 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.
- Sign up at agentroost.app — takes about 60 seconds with email, Google, Microsoft, or Discord.
- Pick the n8n framework, give your instance a name.
- Your private n8n editor opens at
https://<your-id>.agentroost.app. No Docker, no SSL cert wrangling. - 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.
- 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 or go straight to the n8n agent page 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-priorityregardless 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.
Frequently asked questions
Do I need to bring my own OpenAI API key to use the AI node in n8n on AgentRoost?
No. AgentRoost includes LLM credits with every subscription. The AI nodes are pre-wired — you pick a model and start classifying without entering any API key. This is the main difference from self-hosting n8n or running it on a generic VPS where you would pay for API calls separately.
Which model should I use for ticket classification at high volume?
A small, fast model is the right call. google/gemini-flash-1.5, meta-llama/llama-3.1-8b-instruct, and anthropic/claude-3-haiku all handle closed-list classification accurately and are far cheaper than frontier models. Classification prompts are short, so the cost per ticket stays low even at thousands of tickets per month. On AgentRoost you can switch models at any time without reconfiguring credentials.
What happens if the LLM returns a label that is not in my list?
The Switch node's fallback output fires. Wire that fallback to a general queue and add a Slack alert so the team can spot if the prompt is drifting. The strict system prompt reduces out-of-vocabulary outputs to a very small fraction of runs, but always have a fallback path rather than letting tickets silently drop.
Can I export my workflows and data if I decide to leave?
Yes. It is your own n8n instance. You can export every workflow as JSON from the n8n editor at any time. Your data is yours — there is no proprietary format or lock-in.
Is there a free trial?
There is no free tier, but every plan comes with a 14-day money-back guarantee. If the workflow does not deliver value within two weeks, you can request a full refund — no questions asked.