Jev API integration
New accounts start with a $0 balance — top up before your first request. Top up from $5. If a request returns 402 (400 on the OpenAI format) with "wallet balance is insufficient", your balance is empty — your base URL and key are fine. Top up and retry.
Understand Jev
Jev, by TypeSafe, is a decision model, not a chat model. Give it a piece of text and a question, and it answers directly: which category, what score, yes or no. The result is ready for your code to use. For example, route a "charged twice" complaint to the billing team, or score a review.
It uses the TypeSafe API. OpenAI Chat Completions is not compatible, and Jev cannot be used as the chat model in Codex or Claude Code.
Get an API key
Get your TeamoRouter API key from the dashboard and store it in the TEAMOROUTER_API_KEY environment variable. Existing keys work as they are; no TypeSafe account is needed.
Integrate with the official SDK
For the text examples below, point the official TypeSafe SDK's base_url at TeamoRouter and use your TeamoRouter API key. The SDKs default to jev-latest; on TeamoRouter set the model to jev-1.14.0. For images, use the tested JSON/base64 format below.
Python (pip install typesafe-sdk):
import os
from typesafe_sdk import Choice, TypeSafeClient
client = TypeSafeClient(
api_key=os.environ["TEAMOROUTER_API_KEY"],
base_url="https://api.teamorouter.com", # the only line that changes
model="jev-1.14.0",
)
response = client.system_one(
state="I was charged twice for the same order.",
questions={
"department": Choice(
instructions="Which team should handle this customer message?",
criteria={
"billing": "Charges, payments and refunds",
"technical": "Bugs and integration issues",
"other": "Other requests",
},
),
},
)
print(response.answers["department"])
TypeScript (npm install @typesafe-ai/sdk):
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient({
apiKey: process.env.TEAMOROUTER_API_KEY,
baseURL: "https://api.teamorouter.com", // the only line that changes
});
const response = await client.systemOne({
model: "jev-1.14.0",
state: "I was charged twice for the same order.",
questions: {
department: choice("Which team should handle this customer message?", {
billing: "Charges, payments and refunds",
technical: "Bugs and integration issues",
other: "Other requests",
}),
},
});
console.log(response.answers.department);
Call the endpoint directly
Send POST https://api.teamorouter.com/v1/systemone with an Authorization: Bearer <TeamoRouter API key> header. The request body follows the TypeSafe schema. This example routes a duplicate charge complaint to billing, technical or other:
curl --fail-with-body 'https://api.teamorouter.com/v1/systemone' \
-H "Authorization: Bearer $TEAMOROUTER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "jev-1.14.0",
"state": "I was charged twice for the same order.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this customer message?",
"criteria": {
"billing": "Charges, payments and refunds",
"technical": "Bugs and integration issues",
"other": "Other requests"
}
}
}
}'
Read the answer
Read answers.department.choice for the category, probabilities for its distribution and confidence for the classification confidence.
| Type | Criteria | Answer |
|---|---|---|
choice |
Option names mapped to descriptions | choice, probabilities, confidence |
score |
An ordered array of 2–10 rubric levels | score, legend, probabilities, confidence; scores may be fractional |
noul |
Optional true and false descriptions |
noul: the probability of yes, from 0 to 1 |
Questions are evaluated independently against the same state. Their answers are keyed by the question names. One answer is not automatically passed to the next question. See TypeSafe primitives for the full question syntax.
Send an image (verified on dev)
jev-1.14.0 accepts PNG/JPEG images in the top-level assets map. Reference the image by its key in state or a question, and send TypeSafe-Danger-Zone-Images: true on each request. This Python example uses the dev endpoint where the JSON/base64 path passed an end-to-end test. Production availability depends on deployment. Multipart image uploads from the official SDK have not been verified through TeamoRouter.
import base64
import os
from pathlib import Path
import requests # pip install requests
photo = base64.b64encode(Path("photo.png").read_bytes()).decode("ascii")
response = requests.post(
"https://teamorouter-dev.teamolab.com/v1/systemone",
headers={
"Authorization": f"Bearer {os.environ['TEAMOROUTER_API_KEY']}",
"TypeSafe-Danger-Zone-Images": "true",
},
json={
"model": "jev-1.14.0",
"state": {"photo": "photo-1"},
"assets": {
"photo-1": {"type": "image", "format": "png", "data_base64": photo}
},
"questions": {
"person_present": {
"type": "noul",
"instructions": "Is there a person in `photo`?",
},
"person_location": {
"type": "box",
"instructions": "Locate the person in `photo`.",
},
},
},
timeout=60,
)
response.raise_for_status()
print(response.json()["answers"])
For JPEG, change format to jpg. A box answer uses coordinates from 0 to 1 relative to image size. Images and box are experimental TypeSafe features.
Check pricing and limits
Available versions include jev-1.14.0 and jev-1.13.0; use the exact model ID from the live catalog. See live pricing for the current rate. State plus the longest question must fit within 32K tokens; state plus all questions must fit within 64K. A choice supports up to 255 options and a score uses 2–10 levels. English works best; validate other languages with your own examples.
Do not send messages, stream, temperature or max_tokens.
Troubleshoot calls
- 401: check the key and the
Authorization: Bearerheader. - 400: check
state,questions, the question type andcriteria; the error message names the field. - 404: confirm the
/v1/systemonepath. - 429: you exceeded the rate limit; retry with exponential backoff. The official SDKs retry automatically.
See the TypeSafe API reference for the native schema.