Skip to content

Automation  ·  Customer success

How to build support ticket routing

A severity one from your largest customer sits behind a password reset because both arrived at 9am. Below is the model behind routing that knows the difference, the prompts that build it, and the parts that only bite once it is live.

Built with Tray Headless

  1. System Zendesk
  2. Step Classify
  3. Step Derive priority
  4. Step Route on skill
  5. Step Assign
  6. System Slack
Also Salesforce

Priority is derived from contract and impact rather than chosen by the requester, and the clock runs from when the customer wrote.

The short answer

What is support ticket routing?

There are four parts to support ticket routing: classification that reads the ticket rather than trusting the dropdown, priority derived from contract entitlement and business impact instead of chosen by the requester, routing on the skill required rather than on who happens to be free, and a clock that starts when the customer wrote. The part teams get wrong is trusting the requester priority. Given a dropdown everybody picks urgent, so the field carries no information and the real outage queues behind a password reset.

What matters here

  • Never trust the priority the requester picked. Given the option everything is urgent, which is the same as nothing being urgent.
  • Derive priority from contract entitlement and business impact. Those are facts the system holds and the requester does not.
  • Route on the skill the ticket needs, not on who is idle. A fast wrong assignment costs a reassignment and a customer explaining twice.
  • Start the clock when the customer wrote, not when somebody opened it. The queue is the part you control.
  • Reassignment count is the honest measure of routing quality. Nobody reports it and it tells you more than first response time.

Who this is for

You run support operations. Tickets are triaged by whoever is on rota, priority is whatever the customer selected, and the escalations that matter are found by somebody scanning the queue.

How it works in practice

What has to happen between a customer writing in and the right person picking it up.

  1. 1

    The ticket is classified from its content

    Product area, symptom and whether it is a question, a bug or a request. Not from a dropdown the customer guessed at.

  2. 2

    Priority is derived, never taken from the form

    Contract entitlement, how many users are affected, and whether there is a workaround.

  3. 3

    Account context is attached before assignment

    Contract value, renewal date, open escalations and current health, so whoever picks it up already knows.

  4. 4

    Routing goes to the skill, then to a person

    The queue that can solve it first, then the least loaded qualified agent who is actually online.

  5. 5

    The clock starts when the customer wrote

    Not when a human opened it. The gap between those two is queue time and it belongs to you.

  6. 6

    Anything breaching an entitlement escalates before it breaches

    With the account owner told, because a severity one on a renewal account is commercial.

What ticket routing is made of

Four pieces, and the second is where most queues go wrong.

Classification from content

Product area and symptom read from what the customer wrote, because the dropdown is a guess made by somebody who does not know your taxonomy.

Derived priority

Entitlement, user impact and workaround availability. Facts the system holds, rather than a self-assessment.

Skill-based routing

To the queue that can resolve it, then to a qualified agent who is online. Availability is the tiebreak, not the rule.

A customer-side clock

Time from the customer writing to a human reply. Anything else measures the team, not the experience.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    Set up and gather the entitlement picture

    Priority depends on facts that live outside the ticket.

    Headless skills build-workflow

    Use build-workflow. The systems in play are Zendesk and Salesforce, or
    whatever we run in those seats.
    
    From Zendesk I need the Ticket model: status, priority, tags,
    group_id, assignee_id and the custom fields in play, plus the group
    and agent skill definitions. From Salesforce I need Account and
    Contract with contract value, renewal date, support tier and any open
    escalation.
    
    The entitlement is the part that matters. Tell me where support tier
    actually lives, because it is usually on a contract line rather than the
    account, and routing that reads the wrong one is worse than no routing.
  2. 2

    Classify from the content, not the dropdown

    The customer is guessing at a taxonomy they have never seen.

    Headless skills build-workflow

    Use build-workflow. On ticket creation, classify from subject and body:
    
      Product area, from our own list
      Symptom type: broken, confusing, missing, or a question
      Whether the customer states a workaround exists
      How many users they mention being affected
      Language, if we route by it
    
    Treat the customer's own category and priority selections as weak signals
    only. They are guessing at a taxonomy they have never seen, and a
    mis-tagged ticket routed confidently is worse than an untagged one.
    
    Where classification confidence is low, route to general triage rather
    than guessing at a specialist queue.
  3. 3

    Derive the priority from facts, not the form

    Given a dropdown, everything is urgent.

    Build priority from a matrix over entitlement and impact:
    
      Impact: users affected, and whether a workaround exists
      Entitlement: the support tier on the contract
      Multiplier: an existing open escalation on the account, or a renewal
      inside the next quarter
    
    Never take the requester's priority as the answer. Store it, so a large
    gap between what they chose and what was derived is visible, but do not
    route on it.
    
    That gap is worth reporting. A customer consistently marking everything
    urgent is a relationship signal, and so is one who never does and then
    has an outage.

    Storing the requester priority alongside the derived one is what lets you defend the routing when somebody asks why their urgent ticket was not treated as urgent.

  4. 4

    Route on skill, use availability as the tiebreak

    A fast wrong assignment costs a reassignment and a customer repeating themselves.

    Headless skills tray-gotchas

    Use tray-gotchas, then route:
    
      1. To the queue whose skills match the product area and symptom
      2. Within that queue, to a qualified agent who is online and under
         their concurrent limit
      3. Following the sun where the tier entitles it
      4. To a named escalation path for the top tier, not a general pool
    
    Attach the account context before assignment: contract value, renewal
    date, open escalations, health, and the last three tickets. Whoever picks
    it up should not have to go and look.
    
    Handle these: an agent going offline mid-ticket, a queue with nobody
    available, a reopened ticket which should return to the original agent
    where possible, and a ticket that turns out to belong to another team.
  5. 5

    Time it from the customer, and measure reassignment

    One of these is the experience and the other is the honest quality measure.

    Stamp when the customer wrote, when it was assigned, and when a human
    first replied. First response time is the first to the last.
    
    Escalate before an entitlement breaches, not after. A warning at eighty
    percent of the target is actionable; a breach report is an apology.
    
    Then report: first response and resolution against entitlement by tier,
    reassignment count per ticket, misroute rate by queue, and tickets where
    the derived priority differed sharply from the requester's.
    
    Reassignment count is the measure of routing quality and almost nobody
    reports it. Every reassignment is a customer explaining themselves
    twice.
  6. 6

    Validate it, then hand the matrix to support ops

    Because the skills map changes with every hire.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production.
    
    Then open the same workflow in Tray Build so support operations can
    maintain the skills map, the priority matrix and the escalation paths in
    the visual canvas. Those change with every hire and every new product
    area.

What it connects to

The ticket says what, the CRM says who, and both decide where it goes.

Zendesk

Read tickets and agent skills, write the derived priority, the routing and the account context.

Reads and writes

Salesforce

Read contract value, support tier, renewal date and open escalations, which is what priority is derived from.

Reads

Slack

Tell the assigned agent with the context attached, and warn the account owner before an entitlement breaches.

Writes

PagerDuty

Page for a severity one out of hours, because an email will not wake anybody.

Writes

Jira

Escalate a confirmed defect with the ticket history attached, not retyped.

Writes

Snowflake

Land routing decisions and outcomes, so misroute rate by queue is measurable rather than argued about.

Writes

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, Google BigQuery, Microsoft Teams, ServiceNow, HubSpot or Databricks.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

This decides who sees a customer problem and how fast. It carries contractual obligations.

It runs where production runs, not on a laptop

Every inbound ticket is classified and routed within seconds of arriving, including the surge when something breaks and a hundred customers write at once.

Every routing decision is explainable

Which classification, which priority inputs, which queue and why. When a customer asks why their ticket waited, that is the answer.

No credential ever lands in the workflow itself

The support credential reads customer conversations, which are among the most sensitive text you hold. Held in your workspace and scoped.

Support ops owns the matrix

Skills, priority inputs and escalation paths open in Tray Build, maintained by the team that runs the rota.

Warn before a breach, not after

Escalation at eighty percent of the entitlement target. A breach report is an apology and a warning is an action.

Questions people ask

Why not use the priority the customer selected?

Because given a dropdown, everybody picks urgent, so the field carries no information. Deriving priority from entitlement and impact uses facts the system holds rather than a self-assessment.

Why classify from content instead of the category field?

Because the customer is guessing at a taxonomy they have never seen. Reading the subject and body gives a better answer, and low confidence should route to general triage rather than a confident wrong queue.

Why route on skill, not availability?

Because a fast assignment to somebody who cannot solve it costs a reassignment and a customer explaining themselves twice. Availability is the tiebreak within a qualified queue, not the rule.

When should the clock start?

When the customer wrote. The gap between that and a human opening it is queue time, which is the part support actually controls and the part measuring from assignment hides.

What is the most underused metric?

Reassignment count per ticket. It is the honest measure of routing quality, almost nobody reports it, and every reassignment is somebody repeating themselves.

Vibe-coding app guides

Vibe-code an entire app with Helix

This moves the data between systems. It does not give anybody a screen to work in. Build that app in Claude Code, Codex or Cursor, then deploy and run it governed on Tray Helix. Same kind of guide, same kind of prompts.

How to build a customer escalation tracker (opens helix.tray.ai in a new tab)

Further reading

Background on the same subject, for the case rather than the build.

Last reviewed September 2026.