How to use Jev: a quickstart
To use Jev, get an API key from the TypeSafe console, then send a POST request with a state and a map of typed questions to https://api.typesafe.ai/v1/systemone, using the model jev-latest (Quick start). You get back one typed answer per question, with probabilities and, for Choice and Score questions, a confidence number your code can branch on.
Step 1: Try it in the Playground
You can test Jev before writing code. Open the Playground, sign in, paste any text as the state, and add a question. The quickstart suggests a support message and the Noul question "Does this message express urgency?" Then add a Choice and a Score question to see several answers from one call.
Access is through TypeSafe's console. The launch post says Jev is in early access, with developers being admitted from a waitlist (launch post).
Step 2: Call the HTTP API
Create a key on the console's keys page and set it as TYPESAFE_API_KEY. This is the quickstart's own cURL example:
curl -X POST https://api.typesafe.ai/v1/systemone \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'EOF'
{
"state": "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.",
"model": "jev-latest",
"questions": {
"urgency": {
"type": "noul",
"instructions": "Does this message express urgency?"
}
}
}
EOF
Every request has three required fields (API reference):
state: the content to evaluate, as a string, JSON object, or array.model: use"jev-latest".questions: a map of question names you choose to question objects. Each has atype(noul,choice, orscore),instructions, and usuallycriteria.
For a Choice, criteria maps each option to a description, with up to 255 options. For a Score, it is an ordered list of 2 to 10 levels. For a Noul, it is optional and can describe what true and false mean.
Step 3: Read the response
Answers come back under the names you chose. This is the quickstart's response when it asks the same ticket a Choice, a Score, and a Noul:
{
"model": "jev-1.13.0",
"answers": {
"department": {
"type": "choice",
"choice": "technical",
"confidence": 0.78,
"probabilities": {
"technical": 0.85,
"sales": 0.0,
"billing": 0.15
}
},
"frustration": {
"type": "score",
"score": 1.0,
"confidence": 1.0,
"legend": {
"0": "Calm, just stating facts",
"1": "Frustrated but civil",
"2": "Very angry, strong language"
},
"probabilities": {
"0": 0.0,
"1": 1.0,
"2": 0.0
}
},
"is_urgent": {
"type": "noul",
"noul": 1.0
}
},
"usage": {
"input_tokens": 392,
"output_tokens": 65
}
}
- Choice returns the top option, a probability for every option, and
confidence. - Score returns a probability-weighted
scorethat can land between levels, alegend, the probabilities, andconfidence. - Noul returns one number from 0 (no) to 1 (yes).
The model field shows the exact version that answered, and usage shows the tokens you are billed for. Errors use standard codes: 401 for a bad key, 422 for an invalid request body, 429 for rate limits, and 529 when TypeSafe is overloaded.
Step 4: Use an SDK
TypeSafe publishes client SDKs for Python and JavaScript. Both read TYPESAFE_API_KEY from the environment and retry rate-limited requests by default.
Python
Install with pip install typesafe-sdk or uv add typesafe-sdk (Python 3.10 or newer). The client calls jev-latest by default. From the quickstart:
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient()
ticket = "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP."
response = client.system_one(
state=ticket,
questions={
"department": Choice(
instructions="Which team should handle this",
criteria={
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
"sales": "Pricing or account questions",
},
),
"frustration": Score(
instructions="How frustrated the customer appears",
criteria=[
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language",
],
),
"is_urgent": Noul(
instructions="The message conveys urgency or time-sensitivity",
),
},
)
print(response.answers["department"].choice) # "technical"
print(response.answers["frustration"].score) # 1.0
print(response.answers["is_urgent"].noul) # 1.0
An async client, AsyncTypeSafeClient, has the same system_one method (Python SDK).
JavaScript and TypeScript
Install with npm install @typesafe-ai/sdk (Node.js 20 or newer). The helpers choice(), score(), and noul() build questions. From the JavaScript SDK page:
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const response = await client.systemOne({
state: { document: "I was charged twice. Please fix this ASAP." },
questions: {
category: choice("What is this ticket about?", {
billing: null,
technical: null,
other: null,
}),
},
});
console.log(response.answers.category.choice);
Step 5: Act on confidence
The point of Jev's probabilities is to let code decide when to act alone. TypeSafe suggests three bands: act automatically when confidence is high, confirm or flag when it is medium, and route to a person or another system when it is low. Set stricter thresholds for riskier actions (Confidence). This excerpt from the intent routing pattern sends uncertain messages to a human:
def route_ticket(ticket_id, response):
intent = response.answers["intent"]
complexity = response.answers["complexity"]
if intent.confidence < 0.5:
# If we don't have enough confidence to classify, route to a human agent
return route_to_human_agent(ticket_id)
if intent.choice == "order_status":
handle_order_status(ticket_id)
The docs say the right thresholds depend on your data. Start conservative and adjust after testing. More patterns are collected in the directory's Decision patterns page.
Tips from the docs
- Keep questions atomic. Ask one narrow thing per question and combine answers in code (Introduction).
- Use an object for state so each part has a descriptive name, and send only what the questions need (State).
- Batch questions. All questions in one request share one read of the state, which is cheaper than separate calls.
- Keep math and dates in code. Jev 1.13 does not count, calculate, or compare dates reliably (Jev 1.13 jaggedness).
- Pin a version such as
jev-1.13.0once you have tuned thresholds, becausejev-latestmoves with new releases (Models). - Using a coding agent? Install TypeSafe's agent skill so it writes correct Jev calls.
For project ideas, browse the use-case directory or start with Start here.
Questions
What model name should I use?
Use jev-latest, which currently points to jev-1.13.0. Pin the versioned ID if you need answers to stay stable across releases.
Do I need an SDK to use Jev?
No. You can call POST https://api.typesafe.ai/v1/systemone from any language with a bearer token. The SDKs add typed questions and automatic retries.
How many questions can one request include?
The docs do not set a question count. The limit is context length: 64k tokens per request, and 32k for the state plus the longest question.
How many options can a Choice have?
Up to 255. A Score takes 2 to 10 ordered levels.
Does every answer include confidence?
Choice and Score answers include confidence. Noul answers return a single probability instead.
Can I send JSON as the state?
Yes. State can be a string, a JSON object, or an array of text, and TypeSafe recommends an object for most requests.
More guides: What is Jev?Jev pricing and API costJev vs LLMs: when to use whichJev and MCP: using Jev as a Model Context Protocol toolHow to use Jev with Claude CodeJev in an agentic harness: where it fits in an agent loopJev for orchestration: routing requests, models and skillsJev as a judge: evaluating LLM and agent outputsJev for SEO and GEOJev for ads and ad reviewJev for marketing and lead scoringIs there an open source Jev?Can you fine-tune Jev?Designing questions for JevWhat is RLCD?Jev statistics