# Support ticket triage

Source: https://docs.temprl.org/examples/support-triage

> Route support tickets to the right team, measure how upset the customer is and extract the order number, in one Simo request.

Route each incoming ticket to a team, gauge how upset the customer is, and pull out the order number, in one request. Low-confidence routings go to a triage queue instead of the wrong team.

**Python**

```python
from simoai import Client, Choice, Extract, Noul, Score

c = Client()

QUESTIONS = {
    "team": Choice("Which team should handle this ticket?", {
        "billing":  "charges, refunds, invoices and payment methods",
        "shipping": "delivery, tracking, damaged or missing parcels",
        "account":  "login, password and account settings",
        "tech":     "bugs and errors in the website or app",
    }),
    "mood":    Score("How upset is the customer?", ["calm", "annoyed", "angry", "furious"]),
    "urgent":  Noul("The customer needs an answer today"),
    "order":   Extract("the order number, exactly as written", max_tokens=12),
}

def triage(ticket: str) -> dict:
    r = c.ask({"ticket": ticket}, QUESTIONS)
    team = r["team"]
    return {
        "queue":    team.choice if team.probabilities[team.choice] >= 0.8 else "triage",
        "priority": "high" if r["urgent"].noul > 0.7 or r["mood"].score >= 2.5 else "normal",
        "order":    r["order"].value if r["order"].valid else None,
        "cost":     r.cost_usd,
    }

print(triage("I was charged twice for order A-1042 and nobody answers. Fix it today."))
# {'queue': 'billing', 'priority': 'high', 'order': 'A-1042', 'cost': 2.1e-06}
```

**cURL**

```bash
curl https://api.temprl.org/v1/ask \
  -H "Authorization: Bearer $SIMO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "simo-1-pro",
  "state": {"ticket": "I was charged twice for order A-1042 and nobody answers. Fix it today."},
  "questions": {
    "team": {"type": "choice", "instructions": "Which team should handle this ticket?",
             "criteria": {"billing": "charges, refunds, invoices and payment methods",
                          "shipping": "delivery, tracking, damaged or missing parcels",
                          "account": "login, password and account settings",
                          "tech": "bugs and errors in the website or app"}},
    "mood": {"type": "score", "instructions": "How upset is the customer?",
             "criteria": ["calm", "annoyed", "angry", "furious"]},
    "urgent": {"type": "noul", "instructions": "The customer needs an answer today"},
    "order": {"type": "extract", "instructions": "the order number, exactly as written",
              "kind": "text", "many": false, "max_tokens": 12}
  }
}'
```

**JavaScript**

```javascript
const QUESTIONS = {
  team: {
    type: "choice",
    instructions: "Which team should handle this ticket?",
    criteria: {
      billing: "charges, refunds, invoices and payment methods",
      shipping: "delivery, tracking, damaged or missing parcels",
      account: "login, password and account settings",
      tech: "bugs and errors in the website or app",
    },
  },
  mood: { type: "score", instructions: "How upset is the customer?", criteria: ["calm", "annoyed", "angry", "furious"] },
  urgent: { type: "noul", instructions: "The customer needs an answer today" },
  order: { type: "extract", instructions: "the order number, exactly as written", kind: "text", many: false, max_tokens: 12 },
};

async function triage(ticket) {
  const res = await fetch("https://api.temprl.org/v1/ask", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SIMO_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ model: "simo-1-pro", state: { ticket }, questions: QUESTIONS }),
  });
  if (!res.ok) throw new Error((await res.json()).error?.message);
  const { answers: a } = await res.json();
  return {
    queue: a.team.probabilities[a.team.choice] >= 0.8 ? a.team.choice : "triage",
    priority: a.urgent.noul > 0.7 || a.mood.score >= 2.5 ? "high" : "normal",
    order: a.order.valid ? a.order.value : null,
  };
}
```

## Why it works

- **One read, four answers.** The ticket is read once; the extra questions are almost free.
- **Calibrated routing.** `0.8` on the chosen team means it is right about 80% of the time, so the triage queue catches the genuinely ambiguous tickets, not a random sample.
- **Descriptions do the work.** Each team's description tells the model what belongs there. Keep them specific.
