Ticket routing and escalation with memory
A support ticket needs a few decisions before anyone reads it: which team, how urgent, whether money is involved, and whether a person should step in now. Jepela answers all of them in one call, each as a typed value with probabilities, instead of an LLM that writes text you then parse. Your code reads the numbers and routes.
The problem
- Keyword rules miss the next way a customer phrases the same thing.
- Free text from a language model has to be parsed, and it carries no probability you can set a threshold on.
- The same ticket can need another route for a priority account, and you do not want to pack each account's history into every request.
One request, several answers
The request below asks three questions about one message: a choice of team, a noul for a refund, and a score for urgency. All three are answered in one engine pass. It is copied from the Examples page, where it was sent to a Jepela gateway on 2026-09-23.
{
"state": "Hi, you charged me twice for September. Please send the second payment back.",
"questions": {
"route": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Charges, invoices and refunds",
"support": "Product problems",
"sales": "New licences and upgrades",
"other": "None of these"
}
},
"refund": {
"type": "noul",
"instructions": "Is the customer asking for money back?"
},
"urgency": {
"type": "score",
"instructions": "How urgent is this?",
"criteria": [
"Can wait a week",
"Should be handled today",
"Blocking the customer now"
]
}
},
"model": "jepela-english"
}
The recorded answer: route billing at 0.954 with confidence 0.834, refund 0.934, and urgency 1.557 on levels 0 to 2, nearest "Blocking the customer now". Route on the choice, open a refund case above your threshold, and send low-confidence answers to a person.
The triage cookbook goes one step further: five questions per ticket in one request, and the code reads severity and steps only for bug reports and the refund flag only for billing. Each category comes with its confidence, so a doubtful one can go to a person instead of being trusted.
What memory changes
Write an account's standing facts once, then name the account as the subject on every ticket. This write is copied from the Memory page:
POST /v1/memory/remember
{"subject": "acme", "text": "ACME Logistics holds an enterprise contract.\nRefunds for ACME go to the billing team within one business day."}
Then add "subject": "acme" to the decision. Jepela recalls the lines that share names and phrases with the ticket, places them before it, and lists the lines it used in the answer. With "memory": {"compare": true} the answer also shows the decision without the memory; that second pass is free.
Measured in the escalation cookbook on 2026-09-23, with jepela-english on a test setup:
| Account | Memory lines | Escalate, without and with memory | Route, without and with memory |
|---|---|---|---|
| Northwind Traders (priority) | 2 | 0.20 to 0.82 | support_queue to named_person |
| Contoso (control) | 0 | 0.29 to 0.29 | support_queue to support_queue |
Two facts in memory turned the escalate answer from no to yes and moved the route to a named person. The control account has no memory, so its two answers are the same by construction. The code was the same for both accounts, with no history packed into the request.
Two more effects, measured on 2026-09-26 and described on the Memory page:
- The account's name is searched along with the ticket: a ticket that said only "Our service is down and customers cannot log in." escalated at 0.35 without this and 0.95 with the account's lines.
- A pinned line is sent at every decision about the account, whatever the ticket says: a pinned premium-support line moved the same ticket from 0.35 to 0.86.
POST /v1/memory/rules
{"subject": "acct-7781", "pin": true, "text": "Acct-7781 has premium support: every ticket from them is escalated."}
Pin only what must count every time: every pinned line is read, and billed, at every decision about the account.
Measure on your own labels
Our numbers come from our sets; your tickets are different. The loop from the Quality page:
- Decide, and keep the
decision_idwith the ticket. - Send the right answer with
POST /v1/feedbackwhen you know it. - Read
GET /v1/qualityfor accuracy, calibration error andautomate_at, which gives for a target accuracy such as 0.9, 0.95 or 0.99 a threshold chosen on your labels and whether thresholds chosen that way reached it on labels they were not chosen on, with the share of tickets above them. Automate above the threshold when itsstatusisreached. - Keep a golden set of tickets with known answers, and run it before you change a question, a memory or a model.
Calibration is fitted on your own labels. When a question has 50 labels, Jepela fits a temperature for it and keeps it only if it lowers the calibration error and does not raise the log loss on labels it was not fitted on. On a constructed set of 60 support messages (2026-09-23, through the gateway), the English checkpoint was 83% right, and a fitted temperature lowered its calibration error from 0.17 to 0.13. Your tickets will differ, which is the point of fitting on them.
Limits
From the Jaggedness page, measured on 2026-09-22 and 2026-09-23:
- The engine reads a window of about 475 tokens of state on
jepela-english; the rest is cut, and the answer says so. Send the part that matters, or use"windows": true. - It does not compare numbers or dates. A condition such as
days_since(order.date) > 30goes in code: a memory rule withwhen, orderive. - It does not read negation. A line that names what must not happen makes it more likely; remove such an option with an exclusion rule, which works in code.
- Lines move answers by being there: five neutral lines moved an escalation answer from 0.46 to 0.28. Keep an account's memory short, and check with
"memory": {"placebo": true}. - Recall matches words. A fact worded without the names and terms your tickets use is not found; pin what must always count.
- Answers near a threshold flip on small changes. For expensive actions, require a fired rule or two answers in a row.
- English is the strongest language; other languages are weaker.
Next steps
- Get a key: confirm your email address and pay by card to start at once, or wait for Jepela to approve the account; prepaid credit by card or invoice, $0.042 per million input tokens, output free.
- Cookbooks: the triage and escalation scripts and their outputs.
- Memory and Rules in memory: lines and rules that work.
- Quality: labels, calibration and golden sets.
- Patterns: speculative fan-out, confidence-gated routing and memory-first routing.
- All use cases