Support tickets pile up. Your team drowns in noise whilst critical issues slip through the cracks. Customers get angrier. Someone eventually notices the ticket about the payment system being down, but by then you have lost three high-value customers.

What if every incoming ticket was instantly analysed for urgency, sentiment, and business impact, with critical issues automatically routed to your team in Slack before they become fires?

With ETLR, you can build exactly that. No complex integrations, no ML infrastructure to maintain. Just deploy once and let AI handle the triage.

What We’re Building

A workflow that:

  1. Receives support tickets via webhook from your helpdesk
  2. Analyses urgency with Gemini 2.5 considering frustration, churn risk, and impact
  3. Extracts structured data with validated JSON schema output
  4. Routes critical tickets to Slack with AI reasoning and context
  5. Logs everything else for normal queue processing

The result? Critical tickets in Slack within seconds:

A critical ticket alert as it appears in Slack

The Complete Workflow

Here is the full YAML configuration:

workflow:
  name: ticket-triage
  description: AI-powered ticket triage system that analyses urgency and routes critical tickets to Slack
  environment:
    - name: GEMINI_API_KEY
      secret: true
    - name: SLACK_WEBHOOK_URL
      secret: true
  input:
    type: http_webhook
  steps:
    - type: gemini_chat
      api_key: ${env:GEMINI_API_KEY}
      model: gemini-2.5-flash
      system: |
        You are a customer support ticket triage specialist. Analyze support tickets and determine their urgency level.

        Consider these factors when determining urgency:
        - Customer frustration level (angry language, capital letters, exclamation marks)
        - Threat of cancellation or churn
        - Financial impact (billing issues, overcharges, refunds)
        - Repeated issues ("again", "second time", "still not fixed")
        - Time sensitivity ("by end of day", "immediately", "ASAP")
        - Service disruption (account locked, can't access, broken feature)
      prompt: |
        Please analyze this support ticket:

        Subject: ${ticket.subject}

        Description:
        ${ticket.description}

        Created: ${ticket.created_at}
      output_to: ai_response
      temperature: 0.1
      response_format:
        type: json_schema
        json_schema:
          name: ticket_analysis
          schema:
            type: object
            properties:
              urgency:
                type: string
                enum: ["critical", "high", "medium", "low"]
              suggested_priority:
                type: number
                description: 1-10 (10=highest)
              sentiment:
                type: string
                enum: ["angry", "frustrated", "concerned", "neutral", "positive"]
              reasoning:
                type: string
            required: ["urgency", "suggested_priority", "sentiment"]
    - type: if_else
      if:
        conditions:
          - field: ai_response.urgency
            op: eq
            value: critical
        steps:
          - type: print
            template: 🚨 CRITICAL TICKET - Sending to Slack...
          - type: slack_webhook
            webhook_url: ${env:SLACK_WEBHOOK_URL}
            text_template: |
              🚨 CRITICAL Ticket #${ticket.id}: ${ticket.subject}
              
              Priority: ${ai_response.suggested_priority}/10 | Sentiment: ${ai_response.sentiment}
              
              AI Analysis: ${ai_response.reasoning}
              
              View: ${ticket.link}
      else:
        steps:
          - type: print
            template: 'ℹ️ Ticket #${ticket.id} is ${ai_response.urgency} priority - no immediate alert needed'

Let’s break down each section.

How It Works

1. Webhook Input

input:
  type: http_webhook

The workflow listens for incoming HTTP requests from your helpdesk system. Most support platforms (Zendesk, Intercom, Freshdesk, Help Scout) can send webhooks when tickets are created or updated.

2. AI-Powered Urgency Analysis

- type: gemini_chat
  api_key: ${env:GEMINI_API_KEY}
  model: gemini-2.5-flash
  system: |
    You are a customer support ticket triage specialist. Analyze support tickets and determine their urgency level.

    Consider these factors when determining urgency:
    - Customer frustration level (angry language, capital letters, exclamation marks)
    - Threat of cancellation or churn
    - Financial impact (billing issues, overcharges, refunds)
    - Repeated issues ("again", "second time", "still not fixed")
    - Time sensitivity ("by end of day", "immediately", "ASAP")
    - Service disruption (account locked, can't access, broken feature)
  prompt: |
    Please analyze this support ticket:

    Subject: ${ticket.subject}

    Description:
    ${ticket.description}

    Created: ${ticket.created_at}
  output_to: ai_response
  temperature: 0.1

The Gemini chat step analyses the ticket with a specialist system prompt. We use a low temperature (0.1) for consistent, deterministic classifications rather than creative responses.

The prompt includes multiple urgency indicators:

  • Emotional signals: Angry language, capitals, repeated punctuation
  • Business risk: Churn threats, billing disputes
  • Time pressure: “ASAP”, “urgent”, “immediately”
  • Pattern recognition: “Still broken”, “third time”, “not fixed”

3. Structured JSON Output

response_format:
  type: json_schema
  json_schema:
    name: ticket_analysis
    schema:
      type: object
      properties:
        urgency:
          type: string
          enum: ["critical", "high", "medium", "low"]
        suggested_priority:
          type: number
          description: 1-10 (10=highest)
        sentiment:
          type: string
          enum: ["angry", "frustrated", "concerned", "neutral", "positive"]
        reasoning:
          type: string
      required: ["urgency", "suggested_priority", "sentiment"]

This is where ETLR shines. Instead of parsing freeform AI responses, we enforce a strict JSON schema. The AI must return:

  • urgency: One of four levels
  • suggested_priority: Numerical score 1-10
  • sentiment: Customer emotional state
  • reasoning: Explanation for the classification

No parsing. No validation. Just reliable, structured data you can route on.

4. Conditional Routing

- type: if_else
  if:
    conditions:
      - field: ai_response.urgency
        op: eq
        value: critical
    steps:
      - type: print
        template: 🚨 CRITICAL TICKET - Sending to Slack...
      - type: slack_webhook
        webhook_url: ${env:SLACK_WEBHOOK_URL}
        text_template: |
          🚨 CRITICAL Ticket #${ticket.id}: ${ticket.subject}
          
          Priority: ${ai_response.suggested_priority}/10 | Sentiment: ${ai_response.sentiment}
          
          AI Analysis: ${ai_response.reasoning}
          
          View: ${ticket.link}
  else:
    steps:
      - type: print
        template: 'ℹ️ Ticket #${ticket.id} is ${ai_response.urgency} priority - no immediate alert needed'

The if_else step checks the AI’s urgency classification. Critical tickets trigger an immediate Slack alert with context. Everything else gets logged for normal queue processing.

The Workflow Graph

Here is how the workflow looks in the ETLR dashboard:

The workflow graph showing the decision tree

The if/else branching is clearly visible, showing how critical tickets take the Slack path whilst others get logged.

Environment Variables

The workflow uses two secrets:

  • GEMINI_API_KEY: Your Google AI API key for Gemini
  • SLACK_WEBHOOK_URL: The webhook URL for your Slack channel

Set these in the ETLR dashboard under Environment Variables and mark them as secrets so they are encrypted at rest.

Why This Works

Traditional ticket triage fails because:

  1. Rules are brittle: “If subject contains ‘urgent’” misses 90% of actual urgent tickets
  2. Keywords are gamed: Customers learn to say “urgent” on everything
  3. Context is lost: A billing issue from a $50k customer is different from a free user
  4. Manual triage is slow: By the time someone reads it, the damage is done

AI triage solves this by understanding:

  • Semantic meaning: “I’m cancelling if this isn’t fixed” is urgent even without the word “urgent”
  • Emotional tone: Capital letters and exclamation marks signal frustration
  • Implicit context: “This is the third time” indicates a pattern
  • Business impact: Payment failures are always critical

Customisation Ideas

This is just the starting point. Here are some ways to extend the workflow:

Route to Different Channels

Send different urgency levels to different Slack channels:

- type: if_else
  if:
    conditions:
      - field: ai_response.urgency
        op: eq
        value: critical
    steps:
      - type: slack_webhook
        webhook_url: ${env:CRITICAL_SLACK}
        text_template: "🚨 CRITICAL: ${ticket.subject}"
  else_if:
    - conditions:
        - field: ai_response.urgency
          op: eq
          value: high
      steps:
        - type: slack_webhook
          webhook_url: ${env:HIGH_PRIORITY_SLACK}
          text_template: "⚠️ HIGH: ${ticket.subject}"

Auto-Reply to Low Priority

Acknowledge low-priority tickets immediately:

- type: if_else
  if:
    conditions:
      - field: ai_response.urgency
        op: eq
        value: low
    steps:
      - type: http_call
        url: https://api.yourhelp.desk/tickets/${ticket.id}/reply
        method: POST
        headers:
          Authorization: "Bearer ${env:HELPDESK_API_KEY}"
        body:
          message: "Thanks for reaching out! We'll respond within 24 hours."

Enrich with Customer Data

Look up customer subscription level and adjust priority:

- type: stripe
  api_key: ${env:STRIPE_API_KEY}
  operation: retrieve
  object_type: customers
  object_id: ${ticket.customer_id}
  expand:
    - subscriptions
  output_to: customer_data

- type: if_else
  if:
    conditions:
      - field: customer_data.subscriptions.data[0].plan.nickname
        op: in
        value: ["Enterprise", "Premium"]
      - field: ai_response.urgency
        op: in
        value: ["critical", "high"]
    steps:
      - type: slack_webhook
        webhook_url: ${env:VIP_SLACK}
        text_template: "💎 ${customer_data.subscriptions.data[0].plan.nickname} Customer - ${ticket.subject}"

Track Triage Accuracy

Log AI decisions to your analytics platform:

- type: segment
  write_key: ${env:SEGMENT_WRITE_KEY}
  operation: track
  user_id: ${ticket.customer_id}
  event: Ticket Triaged
  properties:
    ticket_id: ${ticket.id}
    ai_urgency: ${ai_response.urgency}
    ai_sentiment: ${ai_response.sentiment}
    suggested_priority: ${ai_response.suggested_priority}
  output_to: segment_result

Use Multiple AI Models

Compare classifications from different models:

- type: openai_completion
  api_key: ${env:OPENAI_API_KEY}
  model: gpt-4o
  system: "Analyze this support ticket for urgency..."
  prompt: "${ticket.subject} - ${ticket.description}"
  output_to: gpt_analysis

- type: anthropic_chat
  api_key: ${env:ANTHROPIC_API_KEY}
  model: claude-3-5-sonnet
  system: "Analyze this support ticket for urgency..."
  prompt: "${ticket.subject} - ${ticket.description}"
  output_to: claude_analysis

- type: if_else
  if:
    conditions:
      - field: gpt_analysis.urgency
        op: eq
        value: critical
      - field: claude_analysis.urgency
        op: eq
        value: critical
    steps:
      - type: slack_webhook
        text_template: "🚨 CONSENSUS CRITICAL (both models agree): ${ticket.subject}"

Integrating with Your Helpdesk

Most support platforms support webhooks. Here is how to connect them:

Zendesk

  1. Go to Admin → Extensions → Webhooks
  2. Create webhook pointing to your ETLR workflow URL
  3. Trigger on “Ticket Created” events
  4. Map ticket fields to JSON payload

Intercom

  1. Go to Settings → Webhooks
  2. Add webhook with your ETLR URL
  3. Subscribe to conversation.created topic
  4. Test with a sample ticket

Freshdesk

  1. Go to Admin → Workflows → Automations
  2. Create rule: “When ticket is created”
  3. Action: “Trigger webhook” with your ETLR URL
  4. Include ticket details in payload

Custom Integration

If your system does not have webhooks, poll with a cron workflow:

input:
  type: cron
  cron: "*/5 * * * *"  # Every 5 minutes
steps:
  - type: http_call
    url: https://api.yourhelp.desk/tickets?status=new
    output_to: new_tickets
  - type: for_each
    input_from: new_tickets
    steps:
      # ... same AI triage logic

Deploying the Workflow

Save the YAML as ticket-triage.yaml and deploy with one command:

etlr deploy ticket-triage.yaml

That is it. Every new support ticket will be analysed by AI within seconds, with critical issues routed directly to your team.

Ready to stop missing critical tickets? Get started with ETLR or explore the documentation.

Have questions? Join our Discord community or check out more workflow examples.