Jev Case Study: Support Ticket Triage (Full Code)
TL;DR: This Jev case study shows a two-call ticket triage pipeline on Jev 1.13: a choice question assigns each ticket to
billing,technical-support, orsales, and a judgment question decides whether to escalate. Full request bodies, an example-fixture response, and a runnable Python script are below.
Scenario
Our team runs support for a B2B SaaS product with roughly 40,000 tickets per month. Triage used to be the first agent’s job: read the ticket, pick a queue, decide whether it is urgent. It was slow, inconsistent across shift handovers, and it burned senior agents’ time on work a rules engine could not handle — tickets rarely say “billing” outright; they say “I think you charged me twice and I need this fixed today,” and the tone ranges from polite to furious.
We replaced that first pass with two Jev calls per ticket:
- A choice question — assign the ticket to exactly one queue:
billing,technical-support, orsales. - A judgment question — should this ticket be escalated? Answer
yes,no, orunclear.
Jev is a System One judgment model from TypeSafe AI, released in September 2026, built for exactly this kind of work — judgment, choice, and scoring questions — rather than open-ended chat. It returns typed JSON with a confidence value, which is what a triage gate actually needs: route on high-confidence answers, send everything else to a human.
The example ticket below is deliberately typical: a duplicate charge, a same-day deadline, and a bank-dispute threat. It should land in the billing queue and get escalated.
Request
Call 1 — queue assignment (choice question):
{
"model": "typesafe/jev-1.13",
"messages": [
{
"role": "system",
"content": "Choice question. Assign the ticket to exactly one queue: billing, technical-support, or sales. Reply with JSON only: {\"answer\": <queue>, \"confidence\": <0-1>, \"rationale\": <one sentence>}"
},
{
"role": "user",
"content": "Subject: Card charged twice for the September invoice\n\nBody: Hi, I see two charges of $49 on my card from your billing page this morning. Please refund the duplicate charge today, otherwise I will ask my bank to reverse the payment."
}
]
}
Call 2 — escalation check (judgment question):
{
"model": "typesafe/jev-1.13",
"messages": [
{
"role": "system",
"content": "Judgment question. Answer yes, no, or unclear. Reply with JSON only: {\"answer\": <yes|no|unclear>, \"confidence\": <0-1>, \"rationale\": <one sentence>}"
},
{
"role": "user",
"content": "Ticket: Card charged twice for the September invoice. The customer reports a duplicate $49 charge, asks for a same-day refund, and says they will contact their bank otherwise. Should this ticket be escalated?"
}
]
}
Response
Both responses below are example fixtures — illustrative output, not a live capture.
Call 1:
{
"answer": "billing",
"confidence": 0.94,
"rationale": "The customer reports a duplicate charge on an invoice, which is a billing dispute rather than a product defect or a purchase request."
}
Call 2:
{
"answer": "yes",
"confidence": 0.97,
"rationale": "The customer names a same-day deadline and a bank-dispute escalation path, which matches the urgent-financial-impact escalation rule."
}
Reproduce
Save as triage.py, set OPENROUTER_API_KEY, and run python3 triage.py:
import json, os, urllib.request
URL = "https://openrouter.ai/api/v1/chat/completions"
MODEL = "typesafe/jev-1.13" # confirm exact slug on the OpenRouter model page
def ask(system, user):
body = {"model": MODEL, "messages": [
{"role": "system", "content": system},
{"role": "user", "content": user}]}
req = urllib.request.Request(URL, data=json.dumps(body).encode(),
headers={"Authorization": "Bearer " + os.environ["OPENROUTER_API_KEY"],
"Content-Type": "application/json"})
with urllib.request.urlopen(req) as res:
payload = json.load(res)
return json.loads(payload["choices"][0]["message"]["content"])
CHOICE = ('Choice question. Assign the ticket to exactly one queue: '
'billing, technical-support, or sales. Reply with JSON only: '
'{"answer": <queue>, "confidence": <0-1>, "rationale": <one sentence>}')
JUDGE = ('Judgment question. Answer yes, no, or unclear. Reply with JSON only: '
'{"answer": <yes|no|unclear>, "confidence": <0-1>, "rationale": <one sentence>}')
ticket = """Subject: Card charged twice for the September invoice
Body: Hi, I see two charges of $49 on my card from your billing page this
morning. Please refund the duplicate charge today, otherwise I will ask my
bank to reverse the payment."""
queue = ask(CHOICE, ticket)
escalate = ask(JUDGE, "Ticket:\n" + ticket + "\n\nShould this ticket be escalated?")
print(queue)
print(escalate)
Key parameters
| Field | Value | Why it matters |
|---|---|---|
model | typesafe/jev-1.13 | Pin the version so a newer release cannot silently change your triage behavior. Confirm the exact slug on the OpenRouter model page. |
messages[0] (system) | Question type + option list + JSON shape | Jev answers judgment, choice, and scoring questions. Naming the type and the exact options keeps the typed output stable. |
messages[1] (user) | The ticket text | One ticket per call keeps confidence values comparable across calls. |
answer (response) | billing / yes | The decision itself — map it straight to a queue name or an escalation flag. |
confidence (response) | 0.94 / 0.97 (example fixture) | Gate your fallback on it: below your threshold, hand the ticket to a human instead of routing it. |
rationale (response) | One sentence | Enough signal for audit logs without a second model call. |
| Price | $0.0462 per 1M input tokens | At thousands of triage calls per day, cost per call matters. Verify current pricing on OpenRouter before budgeting. |
Notes
- The responses above are example fixtures; verify field names against official docs before relying on them. Official API details live at typesafe.ai — start with the System One announcement post.
- The raw HTTP response is an OpenAI-compatible chat completion; the JSON shown here is the model’s typed output parsed from the message content.
- Confirm the exact model slug (
typesafe/jev-1.13) on the OpenRouter model page before shipping — slugs can change between releases. - Two calls per ticket doubles input tokens. At $0.0462 per 1M input tokens this is still cheap, but you can skip call 2 entirely when call 1 returns low confidence — a low-confidence routing decision should go to a human anyway.
- Keep
unclearin your escalation logic: treat it as “escalate,” not as “no.” - Applies to Jev 1.13 (released September 2026) via the OpenRouter demonstration channel.