Introduction
Support engineers often waste valuable time sorting through tickets to identify urgency, category, or the right assignee. Manual triage slows down response times and creates inconsistencies between agents. Automating this process allows your support system to instantly classify new tickets, prioritize them, and route them to the correct teams or individuals.
In this guide, you will learn how to connect your ticketing platform (Zendesk, Jira, or similar) with an AI model through webhooks and simple Python logic. The result is an intelligent, auditable, and continuously improving routing system.
What We Will Build
- A lightweight automation service that:
- Improves accuracy over time using historical labels
- Listens for new support tickets through webhooks
- Sends ticket text to an AI model for classification
- Assigns priority, category, and the responsible team automatically
- Logs each decision in a database for transparency
Architecture Overview
Step 1: Set Up the Webhook
Your ticketing platform must send new ticket data to your triage service as soon as it is created.
In Zendesk:
- Go to Admin Center → Apps and Integrations → Webhooks → Create Webhook
- Choose HTTP Target and enter your API endpoint, for example:
https://yourserver.com/triage - Set method to POST and format to JSON
- Trigger it on ticket creation events
In Jira:
- Navigate to System → Webhooks → Create a Webhook
- Add URL of your triage service
- Select the Issue Created event
Each event will send a JSON payload containing ticket subject, description, reporter, and other metadata.
Step 2: Build the AI Triage Service
Create a small API endpoint using FastAPI (Python) to receive the webhook payload.
from fastapi import FastAPI, Request
import requests, os
app = FastAPI()
@app.post("/triage")
async def triage_ticket(request: Request):
ticket = await request.json()
subject = ticket.get("subject", "")
description = ticket.get("description", "")
full_text = f"{subject}\n\n{description}"
# Send to AI model for classification
ai_result = classify_ticket(full_text)
# Apply routing logic
update_ticket_system(ticket["id"], ai_result)
return {"status": "processed"}Step 3: Connect to an AI Model
You can use an external API like OpenAI or Claude, or a local LLM via Ollama.
Below is an example using OpenAI for simplicity.
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
def classify_ticket(text):
prompt = f"""
You are a ticket triage assistant.
Categorize and prioritize this ticket.
Ticket:
{text}
Respond in JSON:
{{
"priority": "low|medium|high|urgent",
"category": "bug|feature|billing|technical support|other",
"assignee_group": "frontend|backend|support|finance"
}}
"""
response = openai.ChatCompletion.create(
model="gpt-4-turbo",
messages=[{"role": "user", "content": prompt}],
temperature=0
)
import json
return json.loads(response.choices[0].message["content"])For local processing, replace this function with:
import subprocess, json
def classify_ticket(text):
output = subprocess.run(
["ollama", "run", "mistral", f"Categorize: {text}"],
capture_output=True,
text=True
)
return json.loads(output.stdout)Step 4: Update the Ticket
Once the classification is ready, the triage service updates the ticket’s priority, category, and assignee through the platform’s API.
Zendesk example:
def update_ticket_system(ticket_id, result):
url = f"https://yourcompany.zendesk.com/api/v2/tickets/{ticket_id}.json"
headers = {"Authorization": "Bearer YOUR_TOKEN", "Content-Type": "application/json"}
data = {
"ticket": {
"priority": result["priority"],
"tags": [result["category"]],
"group_id": get_group_id(result["assignee_group"])
}
}
requests.put(url, headers=headers, json=data)Jira example:
Use the REST API to transition issue status or update custom fields with the triage output.
Step 5: Log and Monitor
To maintain transparency and traceability, store each triage decision in a small SQLite or PostgreSQL database.
import sqlite3
def log_decision(ticket_id, result):
conn = sqlite3.connect("triage_log.db")
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS triage_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticket_id TEXT,
priority TEXT,
category TEXT,
assignee_group TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
cursor.execute("""
INSERT INTO triage_log (ticket_id, priority, category, assignee_group)
VALUES (?, ?, ?, ?)
""", (ticket_id, result["priority"], result["category"], result["assignee_group"]))
conn.commit()
conn.close()Add this logging function at the end of your triage_ticket process.
Step 6: Continuous Improvement
To improve accuracy:
- Periodically export tickets that require manual correction
- Feed them back as labeled training examples
- Fine-tune prompts or local models based on recurring mistakes
- Add validation rules to flag low-confidence AI decisions for review
A simple improvement loop might use a confidence threshold:
If the model’s classification probability < 0.6, route the ticket to a “manual review” queue.
Security Considerations
- Validate webhook signatures to prevent spoofing.
- Mask sensitive customer data before sending to AI APIs.
- If using external LLMs, avoid including personally identifiable or confidential data.
- Enforce authentication and HTTPS on your triage API endpoint.
Example Folder Structure
ai-ticket-triage/
│
├── app.py
├── triage_log.db
├── requirements.txt
├── .env
└── utils/
├── ai_client.py
├── ticket_api.py
└── logger.pyReferences and Resources
- Zendesk Webhooks Documentation
- Jira REST API
- LangChain Integration for AI Agents
- OpenAI API Reference
- FastAPI Framework
Conclusion
Automating support ticket triage with AI and webhooks eliminates repetitive manual sorting, reduces time-to-resolution, and enforces consistent prioritization across teams. By combining your existing ticketing platform with a simple AI-powered API, your support team can focus on solving issues rather than sorting them. As you collect more labeled data, the system becomes increasingly accurate and can adapt to your organization’s specific workflow.