Jev is easiest to think of as a typed function call: you send state and questions, you get back answers under the same keys. There is no text to parse, so integration is mostly about where in your pipeline the call sits and what your code does with the confidence value.
This guide uses Flatkey's decisions endpoint, which is what every example on jev-llm.com calls:
POST https://router.flatkey.ai/api/alpha/decisions
Authorization: Bearer $FLATKEY_API_KEY
model: typesafe/jev-1.13
The same request body works on OpenRouter's Decisions API (https://openrouter.ai/api/alpha/decisions, model typesafe/jev-1.14) and, with a different URL, on TypeSafe's own /v1/systemone endpoint. TypeSafe also publishes official SDKs: typesafe-sdk for Python and @typesafe-ai/sdk for TypeScript (TypeSafe docs).
The request shape
{
"model": "typesafe/jev-1.13",
"state": { "ticket": "My card was charged twice for Pro this month." },
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle `ticket`?",
"criteria": {
"billing": "Charges, invoices and refunds",
"technical": "Bugs and outages",
"account": "Sign-in and profile settings"
}
},
"wants_refund": { "type": "noul", "instructions": "Is `ticket` asking for money back?" }
}
}
Three things trip people up:
- Choice criteria are a map (option → description). Score criteria are an ordered list. A Noul needs only
instructions. - Every question needs
instructions. The question id (team) is never shown to the model, so the meaning must be in the instructions and criteria. - Only
choice,scoreandnoulare valid types on Jev 1.13. Names likeenumorbooleanreturn a 400.
Python
import os, requests
URL = "https://router.flatkey.ai/api/alpha/decisions"
def decide(state, questions, model="typesafe/jev-1.13"):
r = requests.post(
URL,
headers={"Authorization": f"Bearer {os.environ['FLATKEY_API_KEY']}"},
json={"model": model, "state": state, "questions": questions},
timeout=30,
)
r.raise_for_status()
return r.json()["answers"]
answers = decide(
{"ticket": "My card was charged twice for Pro this month."},
{"team": {"type": "choice", "instructions": "Which team should handle `ticket`?",
"criteria": {"billing": "Charges, invoices and refunds",
"technical": "Bugs and outages",
"account": "Sign-in and profile settings"}}},
)
team = answers["team"]
if team["confidence"] >= 0.8:
route(team["choice"])
else:
send_to_triage_queue()
Node.js / TypeScript
const URL = "https://router.flatkey.ai/api/alpha/decisions";
export async function decide(state, questions, model = "typesafe/jev-1.13") {
const res = await fetch(URL, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.FLATKEY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ model, state, questions }),
signal: AbortSignal.timeout(30_000),
});
if (!res.ok) throw new Error(`Jev ${res.status}: ${await res.text()}`);
return (await res.json()).answers;
}
Keep the key on the server. Never ship it to the browser.
Patterns that matter in production
- Batch questions, not calls. All questions in one request are answered in parallel against one read of the state, so five questions in one call is far cheaper and faster than five calls. Only split when one question depends on another's answer.
- Gate on confidence. Treat each answer as act / confirm / escalate. Pick thresholds from a few hundred labelled examples, not from intuition.
- Pin the version. If you tuned thresholds on Jev 1.13, keep sending
jev-1.13; switch to 1.14 deliberately after re-checking. - Retry 429s with backoff. Rate limits are per organization; honour
retry-afterwhen present. - Log the distribution, not the state. Log question ids, probabilities and the threshold you applied; keep customer text out of logs.
- Compute exact things in code. Dates, sums and thresholds belong in your code; give Jev the semantic judgment.
Where to go next
Every use case on this site has the same three snippets (curl, Node.js, Python) generated from its real schema, plus a live demo. The What is Jev? page has a combined Choice + Score + Noul example.
FAQ
Which endpoint do the jev-llm.com examples call?
Flatkey's decisions endpoint, POST https://router.flatkey.ai/api/alpha/decisions with model typesafe/jev-1.13. The same request body also works on OpenRouter's Decisions API and, with a different URL, on TypeSafe's own /v1/systemone endpoint.
Why does my Jev request return a 400 error?
On Jev 1.13 the only valid question types are choice, score and noul; names like enum or boolean return a 400. Also check that every question has instructions, Choice criteria are a map and Score criteria are an ordered list.
Should I make one call per question?
No. Put all independent questions in one request: they are answered in parallel against one read of the state, which is cheaper and faster than separate calls. Split only when one question depends on another's answer.
Is there an official Jev SDK?
Yes. TypeSafe publishes typesafe-sdk for Python and @typesafe-ai/sdk for TypeScript. A plain HTTPS request with requests or fetch works too; keep the API key on the server.
Run it on a real workflow
Each use case has a live demo, the exact question schema and copy-paste curl, Node.js and Python code for Flatkey.