Auto-Classify and Route Support Tickets with AI in n8n

AgentRoost · May 15, 2026 · 7 min read · View as Markdown
AgentRoost — AI & LLM How-To

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:

{
  "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 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:

{
  "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 — 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 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-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.

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.