Skip to content
← All templates

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.

llm_callrouterhuman_reviewsla_deadlinetry_catch

What this workflow does

01

Receive ticket — Webhook endpoint accepts POST from your helpdesk (Zendesk, Intercom, custom). Maps subject, body, and customer info to context.

02

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).

03

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.

04

Route to team — Router sends a Slack message to the appropriate channel based on category: #support-billing, #support-technical, #support-product.

05

SLA timer — Per-step deadline based on urgency. Critical: 1 hour. High: 4 hours. Medium: 24 hours. On breach, escalation fires to #support-escalation.

06

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 channels

How 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.