Jein quickstart
Send a support ticket once, then ask which team should handle it, how urgent it is, and whether the customer asks for a refund. The API returns a named, typed answer for each question.
Set up your client
Create an API key and export these two environment variables. Use the service root as the base URL; the SDK adds the versioned path.
export TYPESAFE_BASE_URL=https://app.jein.dev
export TYPESAFE_API_KEY=YOUR_JEIN_API_KEY
The examples below use the same variables and request in every language. Python requires typesafe-sdk==0.7.1; JavaScript requires Node.js 20+ and @typesafe-ai/[email protected].
python3 -m pip install typesafe-sdk==0.7.1
# Or, for a JavaScript project:
npm install @typesafe-ai/[email protected]
Make your first request
POST /v1/systemone evaluates the three questions together. Choose a language, copy the example, and run it after setting your API key. Using a coding agent? Paste the Coding agent prompt instead: it points the agent to /llms.txt, a plain-text guide to the API, and never contains your key.
curl
curl --fail-with-body --silent --show-error "$TYPESAFE_BASE_URL/v1/systemone" \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "laya-latest",
"state": "Hi, I was billed twice for March. Please refund the duplicate.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {"billing": "Payment issues", "technical": "Bugs", "sales": "Sales questions"}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this?",
"criteria": ["Low", "Medium", "High"]
},
"wants_refund": {"type": "noul", "instructions": "The customer asks for a refund"}
}
}'
Python
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
# Reads TYPESAFE_BASE_URL and TYPESAFE_API_KEY.
with TypeSafeClient() as client:
result = client.system_one(
model="laya-latest",
state="Hi, I was billed twice for March. Please refund the duplicate.",
questions={
"department": Choice(
instructions="Which team should handle this?",
criteria={"billing": "Payment issues", "technical": "Bugs", "sales": "Sales questions"},
),
"urgency": Score(
instructions="How urgent is this?",
criteria=["Low", "Medium", "High"],
),
"wants_refund": Noul(instructions="The customer asks for a refund"),
},
)
print(result.model_dump_json(indent=2))
JavaScript
import { choice, noul, score, TypeSafeClient } from '@typesafe-ai/sdk';
// Reads TYPESAFE_BASE_URL and TYPESAFE_API_KEY.
const client = new TypeSafeClient();
const result = await client.systemOne({
model: 'laya-latest',
state: 'Hi, I was billed twice for March. Please refund the duplicate.',
questions: {
department: choice('Which team should handle this?', {
billing: 'Payment issues', technical: 'Bugs', sales: 'Sales questions',
}),
urgency: score('How urgent is this?', ['Low', 'Medium', 'High']),
wants_refund: noul('The customer asks for a refund'),
},
});
console.log(JSON.stringify(result, null, 2));
Coding agent
Set up this project to call the Jein API.
- Read https://app.jein.dev/llms.txt first: it describes the request, the response, the limits and the errors.
- Base URL: https://app.jein.dev. Read it from the environment variable TYPESAFE_BASE_URL.
- The API key is in the environment variable TYPESAFE_API_KEY. Never print, log or commit it.
- Use the TypeSafe SDK: Python typesafe-sdk==0.7.1, or JavaScript @typesafe-ai/[email protected] (Node.js 20+).
- Plain HTTP also works: POST $TYPESAFE_BASE_URL/v1/systemone with the header "Authorization: Bearer $TYPESAFE_API_KEY".
- Use the model laya-latest. GET $TYPESAFE_BASE_URL/v1/models lists every model name.
- Make one working call first, then handle 422 validation errors and retry 429 and 529 after Retry-After.
Read the response
Illustrative response, recorded from a real run of the request above. Model updates can shift the numbers slightly, and your own requests will have different token counts.
{
"model": "laya-0.3.20",
"answers": {
"department": {
"type": "choice",
"choice": "billing",
"confidence": 0.8725,
"probabilities": {
"billing": 0.9736,
"technical": 0.0147,
"sales": 0.0117
}
},
"urgency": {
"type": "score",
"score": 1.1095,
"confidence": 0.1797,
"legend": {
"0": "Low",
"1": "Medium",
"2": "High"
},
"probabilities": {
"0": 0.1311,
"1": 0.6282,
"2": 0.2406
}
},
"wants_refund": {
"type": "noul",
"noul": 0.8793
}
},
"usage": {
"input_tokens": 44,
"output_tokens": 0
}
}
department.choiceis the selected label;probabilitiescontains a probability for every option.confidenceis 1 minus the normalized entropy ofprobabilities: 1.0 when all probability sits on one option, 0.0 when the options are equally likely. It is not the top probability, so billing at 0.9736 has confidence 0.8725, and urgency, spread over three levels, has 0.1797.urgency.scoreis the probability-weighted level from your ordered criteria. It can fall between levels: 1.1095 is Medium, leaning towards High.wants_refund.noulis the probability that the statement is true. Noul has no separate confidence field.usage.input_tokenscounts the state once plus instructions and criteria.output_tokensis zero.modelidentifies the model that answered, even when you send thelaya-latestalias. The TypeSafe SDK defaultjev-latestis accepted too.
Before sending production traffic
Jein currently accepts short inputs. Longer questions leave less room for the state, and oversized requests are rejected rather than truncated. Review the limits, migration checklist, error reference, and OpenAPI contract. Check Usage after your first successful request.
Call the API from your server. A web page on another origin can call it only if that origin is on the service's CORS allow-list, which is empty by default. A key used in a web page is readable by every visitor, and its requests count against your account's allowance: give the page its own key and revoke it on API keys when the page no longer needs it.