Cookbook
Triage Support Requests
Classify and route support tickets with an LLM and switch node.
Receive a support ticket, classify its complexity with an LLM, and route it to the right handler automatically.
webhook support_ticket {
label: "Support Ticket"
enabled: true
schema: @json {
{
"type": "object",
"required": ["ticket_id", "subject", "description", "customer_email"],
"properties": {
"ticket_id": { "type": "string" },
"subject": { "type": "string" },
"description": { "type": "string" },
"customer_email": { "type": "string" },
"priority": { "type": "string" }
},
"additionalProperties": false
}
}
}
graph triage_ticket {
label: "Triage Ticket"
description: "Classify complexity with an LLM, route to the right team"
persistence {
enabled: true
condition: @ts {
return true
}
}
root {
type: code
label: "Parse ticket"
inputSchema: @json {
{
"type": "object",
"required": ["ticket_id", "subject", "description", "customer_email"],
"properties": {
"ticket_id": { "type": "string" },
"subject": { "type": "string" },
"description": { "type": "string" },
"customer_email": { "type": "string" },
"priority": { "type": "string" }
},
"additionalProperties": false
}
}
outputSchema: @json {
{
"type": "object",
"required": ["ticket_id", "subject", "description", "customer_email", "priority"],
"properties": {
"ticket_id": { "type": "string" },
"subject": { "type": "string" },
"description": { "type": "string" },
"customer_email": { "type": "string" },
"priority": { "type": "string" }
},
"additionalProperties": false
}
}
code: @ts {
const { ticket_id, subject, description, customer_email, priority } = context.nodes.root.input
return {
ticket_id,
subject: subject.trim(),
description: description.trim(),
customer_email: customer_email.toLowerCase().trim(),
priority: (priority ?? "normal").toLowerCase(),
}
}
}
node classify {
type: ai
label: "Classify ticket"
kind: object
model: "anthropic/claude-3.5-sonnet"
temperature: 0.2
prompt: @ts {
const { subject, description, customer_email, priority } = context.nodes.root.output
return `Classify this support ticket.
Subject: ${subject}
Description: ${description}
Customer: ${customer_email}
Priority: ${priority}
Return JSON with:
- "complexity": one of "simple", "medium", "complex"
- "category": short label (billing, technical, account, etc.)
- "suggested_response": draft reply if simple, null otherwise`
}
schema: @json {
{
"type": "object",
"required": ["complexity", "category"],
"properties": {
"complexity": { "type": "string", "enum": ["simple", "medium", "complex"] },
"category": { "type": "string" },
"suggested_response": { "type": "string" }
}
}
}
}
node route {
type: switch
label: "Route by complexity"
cases: ["simple", "medium", "complex"]
router: @ts {
return context.nodes.classify.output.complexity
}
}
node auto_respond {
type: email
label: "Auto-respond"
from: @ts { return "[email protected]" }
to: @ts { return context.nodes.root.output.customer_email }
subject: @ts { return `Re: ${context.nodes.root.output.subject}` }
text: @ts {
return context.nodes.classify.output.suggested_response ?? "We've received your request and will follow up shortly."
}
}
node assign_agent {
type: http
label: "Assign to agent"
method: "POST"
url: @ts { return "https://api.example.com/tickets/assign" }
headers: { "Authorization": @ts { return `Bearer ${context.secrets.SUPPORT_API_KEY}` } }
body: @ts {
return JSON.stringify({
ticket_id: context.nodes.root.output.ticket_id,
category: context.nodes.classify.output.category,
priority: "normal"
})
}
}
node escalate {
type: http
label: "Escalate"
method: "POST"
url: @ts { return "https://api.example.com/tickets/escalate" }
headers: { "Authorization": @ts { return `Bearer ${context.secrets.SUPPORT_API_KEY}` } }
body: @ts {
return JSON.stringify({
ticket_id: context.nodes.root.output.ticket_id,
category: context.nodes.classify.output.category,
priority: "urgent"
})
}
}
flow {
root -> classify
classify -> route
route -["simple"]-> auto_respond
route -["medium"]-> assign_agent
route -["complex"]-> escalate
}
}
trigger on_support_ticket {
webhook:support_ticket -> triage_ticket
enabled: true
}How it works
- The webhook receives ticket data from your support system and validates it against the schema.
- The root code node normalizes the payload: trimming whitespace, lowercasing the email, and defaulting priority to
normal. - The AI node classifies complexity (
simple,medium, orcomplex), assigns a category, and drafts a reply for simple tickets. - The switch node reads
complexityfrom the AI output and branches accordingly. - Simple tickets receive an automated email reply using the AI-drafted response.
- Medium tickets are assigned to an agent via your support API with normal priority.
- Complex tickets are escalated via your support API with urgent priority.
- Persistence is enabled unconditionally, so every classification is stored for trend analysis.
Run it
swirls deploySend a test payload to the webhook URL:
curl -X POST https://your-project.swirls.dev/webhooks/support_ticket \
-H "Content-Type: application/json" \
-d '{
"ticket_id": "TKT-001",
"subject": "Cannot log in",
"description": "I reset my password but the link expired.",
"customer_email": "[email protected]",
"priority": "normal"
}'Open the Executions view to inspect the run and verify the branch taken.
Customize
- Add a review node on the simple branch to approve auto-responses before they send.
- Add HTTP nodes before
classifyto fetch customer history and pass it into the prompt. - Query the persistence stream to analyze triage accuracy and tune the prompt over time.
- Swap the webhook for a form trigger to support manual ticket submission.