Ticket routing is the canonical Jev workload: unstructured text in, one of a few queues out, thousands of times a day. TypeSafe's launch material and OpenRouter's walkthrough both use it as the first example (OpenRouter). Here is how to design one that you can actually trust in production.

1. Decide what the router must output

Write the decisions your helpdesk needs, not the ones that are fun to model. A typical set:

  • Team — billing, technical, account, sales (a Choice).
  • Urgency — routine, soon, now (a Score).
  • Refund requested? — a Noul, because it triggers a different workflow.
  • Churn risk? — optional Noul for a retention queue.

2. Send the ticket as structured state

Give Jev the fields it needs and nothing else:

{
  "ticket": "Charged twice for Pro this month — please fix before Friday payroll.",
  "plan": "pro",
  "customer_since": "2024-03"
}

Reference fields by name in instructions ("Which team should handle ticket?"). Do date and money arithmetic in code before the call.

3. Write criteria like routing rules

"team": {
  "type": "choice",
  "instructions": "Which team should handle `ticket`?",
  "criteria": {
    "billing": "Charges, invoices, refunds, plan or seat changes — even if a bug caused the charge",
    "technical": "Errors, outages, broken features, integrations",
    "account": "Sign-in, SSO, passwords, profile and workspace settings",
    "sales": "Pricing questions before purchase, enterprise quotes"
  }
}

The boundary note ("even if a bug caused the charge") is where most routing errors are fixed.

4. Route on confidence, not just the label

a = decide(state, questions)          # see the integration guide
team, conf = a["team"]["choice"], a["team"]["confidence"]

if conf >= HIGH:
    assign(team)
elif conf >= LOW:
    assign(team, flag="check-routing")
else:
    assign("triage")

if a["wants_refund"]["noul"] >= 0.9:
    start_refund_workflow()

HIGH and LOW come from your own data (step 6), not from defaults.

5. Keep it to one request

All four questions go in one call and are answered in parallel, so adding urgency and refund checks costs extra tokens but little latency. OpenRouter measured a three-question ticket call at 447 input tokens, about $0.000019 (OpenRouter) — at that size a million tickets is roughly $19 in model cost.

6. Evaluate before you automate

  1. Export a few hundred recent tickets with the team that finally resolved them.
  2. Run them through the router and record probabilities.
  3. For each confidence band, compute accuracy. Choose HIGH so the auto-assign band's error rate is one your team accepts.
  4. Re-run when you edit criteria or change Jev versions.

7. Operate it

  • Log ticket id, answers and the thresholds applied — not the ticket text.
  • Watch the share of tickets landing in triage; a jump usually means a new topic needs its own option.
  • Add options by editing criteria. No retraining.

Copy the full example

The support-ticket routing use case has this schema with a live demo and curl, Node.js and Python code. Related: intent extraction and steer or queue.

FAQ

How do I route support tickets with Jev?

Send the ticket as structured state and ask a Choice for the team, a Score for urgency and Nouls for refund requests or churn risk, all in one request. Then route on confidence: auto-assign above a high threshold, flag the middle band and send the rest to triage.

How much does Jev ticket routing cost?

OpenRouter measured a three-question ticket call at 447 input tokens, about $0.000019, so a million tickets is roughly $19 in model cost.

How do I fix common routing mistakes?

Write criteria like routing rules with explicit boundary notes, for example that billing owns charges even if a bug caused them. Adding or changing a queue is a criteria edit, with no retraining.

How do I choose the confidence thresholds?

Run a few hundred recent tickets with their final resolving team through the router, compute accuracy per confidence band and pick the auto-assign threshold whose error rate your team accepts. Re-run when criteria or the Jev version change.