Quickstart: first call in HTTP, Python, JS
TL;DR Get a key at https://console.typesafe.ai/settings/keys,
export TYPESAFE_API_KEY=..., thenPOST https://api.typesafe.ai/v1/systemonewithstate,model("jev-latest"), and aquestionsmap. Answers come back under the same keys you chose. Both SDKs readTYPESAFE_API_KEYfrom the environment and default tojev-latest.
Step 1 — get an API key
- Open the console at https://console.typesafe.ai and log in.
- Create a key.
The quickstart page points at the dashboard, https://console.typesafe.ai/settings/keys. The agent-skill page links https://console.typesafe.ai/keys for the same thing — the sources disagree on the exact path; both are under console.typesafe.ai. Use https://console.typesafe.ai and navigate to the API keys page; both paths are cited upstream and the console may redirect. See console.typesafe.ai (console + playground).
Step 2 — set TYPESAFE_API_KEY
export TYPESAFE_API_KEY="sk-..." # your key from the console
Both SDK READMEs say the same thing: "Set TYPESAFE_API_KEY in your environment, then instantiate and use the client." For the HTTP API the key goes in the Authorization header instead. See TYPESAFE_* environment variables across SDKs for every TYPESAFE_* variable.
Step 3 (optional) — try it in the Playground first
- Open the Playground and log in.
- Paste any text as the state:
Hi, I've been trying to connect my Stripe account for 3 days and it keeps failing. I'm losing sales. Please help ASAP.
- Add a question. The docs suggest a Noul:
"Does this message express urgency?"
{
"urgency": {
"type": "noul",
"instructions": "Does this message express urgency?"
}
}
- Add more questions. "Mix Noul, Choice, and Score in one call and see all results at once."
Step 4 — the first call
The endpoint:
POST https://api.typesafe.ai/v1/systemone
Authorization: Bearer <API_KEY>
Content-Type: application/json
Three required body fields: state (string, object, or array), model (string), questions (map of id → question). See HTTP API: POST /v1/systemone and GET /v1/models for every field.
curl
Verbatim from the quickstart, complete and runnable once TYPESAFE_API_KEY is exported:
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 it keeps failing. I'm losing sales. Please help ASAP.",
"model": "jev-latest",
"questions": {
"urgency": {
"type": "noul",
"instructions": "Does this message express urgency?"
}
}
}
EOF
The fuller request body the quickstart documents — one of each primitive in a single call:
{
"state": "Hi, I've been trying to connect my Stripe account for 3 days and it keeps failing. I'm losing sales. Please help ASAP.",
"model": "jev-latest",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this",
"criteria": {
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
"sales": "Pricing or account questions"
}
},
"frustration": {
"type": "score",
"instructions": "How frustrated the customer appears",
"criteria": [
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language"
]
},
"is_urgent": {
"type": "noul",
"instructions": "The message conveys urgency or time-sensitivity"
}
}
}
Python
Install (requires Python >= 3.10):
pip install typesafe-sdk
uv add typesafe-sdk
Use the SDK. The client reads
TYPESAFE_API_KEYfrom the environment and callsjev-latestby default.
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 it 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) # "billing"
print(response.answers["frustration"].score) # 1.035
print(response.answers["is_urgent"].noul) # 0.999
The repo README shows the same call as a context manager, which closes the underlying HTTP client:
from typesafe_sdk import Choice, TypeSafeClient
with TypeSafeClient() as client:
response = client.system_one(
state={"document": "I was charged twice. Please fix this ASAP."},
questions={
"category": Choice(
instructions="What is this ticket about?",
criteria={"billing": None, "technical": None, "other": None},
),
},
)
print(response.choices["category"].choice)
Two things to notice: criteria values may be null/None for options that need no description, and the README reads the answer through response.choices[...] while the docs read response.answers[...]. Both exist on SystemOneResponse — answers is the mixed map, and choices / nouls / scores are per-type views. See Python SDK responses, answers, usage, models. Score.criteria is an ordered sequence in v0.6.0, not an int-keyed dict.
TypeScript / JavaScript
Install (Node.js 20 or newer):
npm install @typesafe-ai/sdk
Verbatim from the SDK README:
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);
Answer types are inferred from your questions. The package includes ESM, CommonJS, and TypeScript declarations.
The same three-question call as the curl and Python samples, using the documented choice(instructions, criteria), score(instructions, criteria), and noul(instructions?, criteria?) helpers (adapted from the README, which shows only choice):
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const ticket =
"Hi, I've been trying to connect my Stripe account for 3 days and it keeps failing. I'm losing sales. Please help ASAP.";
const response = await client.systemOne({
state: ticket,
questions: {
department: choice("Which team should handle this", {
billing: "Payment or subscription issues",
technical: "Bugs or integration problems",
sales: "Pricing or account questions",
}),
frustration: score("How frustrated the customer appears", [
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language",
]),
is_urgent: noul("The message conveys urgency or time-sensitivity"),
},
});
console.log(response.answers.department.choice);
console.log(response.answers.frustration.score);
console.log(response.answers.is_urgent.noul);
See JavaScript/TypeScript SDK: install, client, choice/score/noul for client options and JavaScript SDK interfaces and type aliases for the inferred answer types.
Step 5 — read the answer
The response body for the three-question request, verbatim from the quickstart:
{
"model": "jev-latest",
"answers": {
"department": {
"type": "choice",
"choice": "billing",
"probabilities": {
"billing": 0.84,
"technical": 0.159,
"sales": 0.001
},
"confidence": 0.596
},
"frustration": {
"type": "score",
"score": 1.035,
"legend": {
"0": "Calm, just stating facts",
"1": "Frustrated but civil",
"2": "Very angry, strong language"
},
"confidence": 0.842
},
"is_urgent": {
"type": "noul",
"noul": 0.999
}
},
"usage": {
"input_tokens": 312,
"output_tokens": 48
}
}
What each field means:
| Field | Applies to | Meaning |
|---|---|---|
model |
response | "The model that performed the evaluation." |
answers.<id> |
response | One answer per question, "keyed by the same ids you used in questions." |
type |
every answer | Matches the question's type. |
choice |
Choice | "The highest-probability option." |
score |
Score | "The probability-weighted answer across the levels; can land between levels." |
noul |
Noul | "The yes/no answer on a scale from 0 (no) to 1 (yes)." |
probabilities |
Choice, Score | Every option or level mapped to its probability ("floats that sum to 1"). |
legend |
Score | "Each level number mapped back to its description." |
confidence |
Choice, Score | "How certain the model is, derived from probabilities." Noul has no confidence. |
usage.input_tokens / usage.output_tokens |
response | Token usage for the request. |
Note that the quickstart's example answers omit probabilities on the Score answer even though raw/docs/api.md marks it required; raw/docs/api.md is the contract. Branch on these values in code — do not re-parse prose. See Confidence vs probability before you pick thresholds.
Step 6 — errors and retries
| Status | Meaning |
|---|---|
401 Unauthorized |
"Missing or invalid API key. Check the Authorization header." |
422 Unprocessable Entity |
"The request body failed validation — for example a missing required field or a malformed question." |
429 Too Many Requests |
"You have exceeded your rate limit. Back off and retry after a short delay." |
529 Overloaded |
"TypeSafe is temporarily overloaded. Retry after a short delay." |
When you receive a
429 Too Many Requestsor529 Overloadedresponse, retry the request with exponential backoff instead of retrying immediately. Our client SDKs handle this automatically, so no extra handling is needed if you use one of our SDKs with its default retry policy.
See HTTP status codes, rate limits, retry semantics.
Step 7 (optional) — install the agent skill
Install the TypeSafe skill using the Claude Code plugin or
npx skills add typesafe-ai/skills --skill typesafe-ai.
claude plugin marketplace add typesafe-ai/skills
claude plugin install typesafe@typesafe-ai
npx skills add typesafe-ai/skills --skill typesafe-ai
Then "tell your coding agent to use the TypeSafe skill as you build." The docs' starter prompt:
Let's build a simple CLI that uses the TypeSafe API to evaluate a set of supplied documents on multiple dimensions. Use the TypeSafe skill to understand how to use the TypeSafe API and how to structure the system. Ask me questions about what kinds of documents I want to evaluate and on what dimensions.
Full details in The typesafe-ai agent skill and Claude Code plugin.
Checklist
- Key created at console.typesafe.ai
-
TYPESAFE_API_KEYexported (or passed to the client explicitly) - One call returning
200with answers under your own question ids - Questions and thresholds kept in one file, not scattered through handlers
- Model pinned (
jev-1.13.0) if you have tuned thresholds —jev-latestmoves
Next steps
- Primitives: Choice, Score, Noul — "How to define questions, choose between Choice, Score, and Noul, and ask several at once"
- Choosing between Choice, Score, Noul — picking the right question type
- Confidence vs probability — "How TypeSafe reports certainty, and how to use it architecturally"
- Patterns overview — "Common patterns for building systems with TypeSafe"
- AI primer: why calibrated decision models — "Why TypeSafe trains models for calibrated decisions instead of generated text"
- HTTP API: POST /v1/systemone and GET /v1/models — every request and response field
- Python SDK: install, clients, system_one() / JavaScript/TypeScript SDK: install, client, choice/score/noul — installation options and detailed usage
- Models, aliases, pricing, rate limits, context — aliases, price, rate limits, context window
- Cookbooks overview — worked end-to-end examples
- Playbook for LLM agents building with Jev — if you are an agent building with Jev
Related
- System One Models — what Jev is and why the output is typed
- State: what you send Jev — what to put in
state - console.typesafe.ai (console + playground) — the console and playground
- TYPESAFE_* environment variables across SDKs —
TYPESAFE_*variables - Smart home assistant demo walkthrough — a worked application
Sources
- raw/docs/introduction__quickstart.md (https://docs.typesafe.ai/introduction/quickstart)
- raw/docs/introduction.md (https://docs.typesafe.ai/introduction)
- raw/github/typesafe-sdk-python/README.md (https://github.com/typesafe-ai/typesafe-sdk-python)
- raw/github/typesafe-sdk-js/README.md (https://github.com/typesafe-ai/typesafe-sdk-js)
- raw/docs/api.md (https://docs.typesafe.ai/api)