CalibratedDecisions.

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):

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
  }
}

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

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