AI Support Triage
Webhook receives a support ticket, an LLM classifies urgency and category, the ticket routes to the right team channel, and escalation fires automatically on SLA breach. Ambiguous cases go to human review.
What this workflow does
Receive ticket — Webhook endpoint accepts POST from your helpdesk (Zendesk, Intercom, custom). Maps subject, body, and customer info to context.
LLM classification — Calls your LLM provider (OpenAI, Anthropic, etc.) with a structured prompt. Returns urgency (critical/high/medium/low) and category (billing/technical/feature/account).
Confidence check — If the LLM confidence is below 0.7, routes to human review with a 30-minute deadline. The human can override the classification.
Route to team — Router sends a Slack message to the appropriate channel based on category: #support-billing, #support-technical, #support-product.
SLA timer — Per-step deadline based on urgency. Critical: 1 hour. High: 4 hours. Medium: 24 hours. On breach, escalation fires to #support-escalation.
Log & update CRM — Writes classification result to your audit log and updates the ticket status in your helpdesk via API.
Workflow definition
Copy this JSON and POST it to /sequences.
{
"id": "ai_support_triage_v1",
"context_schema": {
"ticket_id": "string",
"subject": "string",
"body": "string",
"customer_email": "string",
"customer_plan": "string"
},
"blocks": [
{
"id": "classify",
"type": "step",
"handler": "llm_call",
"params": {
"provider": "openai",
"model": "gpt-4o-mini",
"api_key_env": "OPENAI_API_KEY",
"system": "You are a support ticket classifier. Return JSON with: urgency (critical|high|medium|low), category (billing|technical|feature|account), confidence (0-1), summary (1 sentence).",
"messages": [
{
"role": "user",
"content": "Subject: {{context.data.subject}}\nBody: {{context.data.body}}\nCustomer plan: {{context.data.customer_plan}}"
}
]
}
},
{
"id": "confidence_check",
"type": "router",
"routes": [
{
"condition": "steps.classify.output.parsed.confidence < 0.7",
"blocks": [
{
"id": "human_review",
"type": "step",
"handler": "human_review",
"params": {
"review_data": "LLM classified ticket #{{context.data.ticket_id}} as {{steps.classify.output.parsed.category}}/{{steps.classify.output.parsed.urgency}} with {{steps.classify.output.parsed.confidence}} confidence."
},
"wait_for_input": {
"prompt": "Review classification for ticket #{{context.data.ticket_id}}. Subject: {{context.data.subject}}",
"choices": [
{ "label": "Accept classification", "value": "accept" },
{ "label": "Billing", "value": "billing" },
{ "label": "Technical", "value": "technical" },
{ "label": "Feature request", "value": "feature" },
{ "label": "Account", "value": "account" }
],
"store_as": "human_classification",
"timeout": 1800000
}
}
]
}
]
},
{
"id": "route_to_team",
"type": "router",
"routes": [
{
"condition": "steps.classify.output.parsed.category == 'billing'",
"blocks": [
{
"id": "notify_billing",
"type": "step",
"handler": "ap://slack.send_channel_message",
"params": {
"auth": { "access_token": "credentials://slack-bot" },
"props": {
"channel": "#support-billing",
"text": "Ticket #{{context.data.ticket_id}} ({{steps.classify.output.parsed.urgency}}): {{steps.classify.output.parsed.summary}}\nCustomer: {{context.data.customer_email}} ({{context.data.customer_plan}})"
}
},
"deadline": 3600000,
"on_deadline_breach": {
"handler": "ap://slack.send_channel_message",
"params": {
"auth": { "access_token": "credentials://slack-bot" },
"props": {
"channel": "#support-escalation",
"text": "SLA BREACH: Ticket #{{context.data.ticket_id}} — {{steps.classify.output.parsed.urgency}} billing issue unresolved."
}
}
}
}
]
},
{
"condition": "steps.classify.output.parsed.category == 'technical'",
"blocks": [
{
"id": "notify_technical",
"type": "step",
"handler": "ap://slack.send_channel_message",
"params": {
"auth": { "access_token": "credentials://slack-bot" },
"props": {
"channel": "#support-technical",
"text": "Ticket #{{context.data.ticket_id}} ({{steps.classify.output.parsed.urgency}}): {{steps.classify.output.parsed.summary}}\nCustomer: {{context.data.customer_email}}"
}
}
}
]
}
],
"default": [
{
"id": "notify_product",
"type": "step",
"handler": "ap://slack.send_channel_message",
"params": {
"auth": { "access_token": "credentials://slack-bot" },
"props": {
"channel": "#support-product",
"text": "Ticket #{{context.data.ticket_id}} ({{steps.classify.output.parsed.category}}): {{steps.classify.output.parsed.summary}}"
}
}
}
]
},
{
"id": "log_result",
"type": "step",
"handler": "log",
"params": {
"level": "info",
"message": "Ticket {{context.data.ticket_id}} classified",
"data": {
"urgency": "{{steps.classify.output.parsed.urgency}}",
"category": "{{steps.classify.output.parsed.category}}",
"confidence": "{{steps.classify.output.parsed.confidence}}"
}
}
}
]
}Credentials to configure
openaiapi_keyOpenAI API key. Swap to anthropic, google, or any supported provider.slack-botoauth2Slack bot token with chat:write scope for all support channelsHow to trigger
// POST /triggers
{
"type": "webhook",
"sequence_id": "ai_support_triage_v1",
"config": {
"path": "/hooks/support-ticket",
"hmac_secret": "credentials://zendesk-hmac"
},
"context_mapping": {
"ticket_id": "body.ticket.id",
"subject": "body.ticket.subject",
"body": "body.ticket.description",
"customer_email": "body.ticket.requester.email",
"customer_plan": "body.ticket.requester.plan"
}
}Works with Zendesk webhooks, Intercom webhooks, or any system that POSTs ticket data.
Customize it
Swap LLM provider — change provider to anthropic, google, or groq for faster/cheaper classification.
Add auto-response — insert an email step after classification to send an acknowledgment to the customer with estimated response time based on urgency.
Multi-language — add a language detection step before classification. Route non-English tickets to a translation step first.
Sentiment analysis — extend the LLM prompt to also return sentiment. Route angry customers to a dedicated retention channel.