Start building / Guide 01 · TypeScript · Beginner
Your first Jev request.
A complete walkthrough for routing a support message to a department with TypeScript: install the SDK, configure a key, send one request, and read the typed answer it returns.
Prerequisites and setup
- Node.js 20 or newer.
- A TypeSafe API key from the TypeSafe console.
- Install the official SDK:
npm install @typesafe-ai/sdk
Configure your API key securely
Set TYPESAFE_API_KEY as a server-side environment variable. new TypeSafeClient() reads it automatically; you never pass the key as a literal. Keep it out of any file you commit — use an .env file listed in .gitignore, or your platform's secret manager — and never send it to the browser: this call belongs on a server, not in client-side code.
The complete example
This is the same file used to generate the homepage excerpt and the message-routing recipe's own code panel, so it can never drift from what those pages show.
// Recipe: Route a message — classify a customer message into a department with Jev.
// Requires Node.js 20+ and TYPESAFE_API_KEY in the environment.
// npm install @typesafe-ai/sdk
// Generated from the same code path as the live example on /recipes/message-routing;
// see scripts/generate-recipe-examples.mts. Not executed against the live API by this guide.
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient(); // reads TYPESAFE_API_KEY, defaults to jev-latest
const message = "Hi, I was charged twice for my subscription this month. The two charges show up on my card statement on the 3rd and the 4th. Can you refund one of them?";
const { answers } = await client.systemOne({
state: message,
model: "jev-latest",
questions: {
department: choice(
"Which department should handle this customer message?",
{
billing: "Charges, invoices, refunds, payment methods, subscription costs",
account: "Login, password, profile, permissions, closing or changing an account",
technical: "Bugs, errors, outages, integrations, something not working",
sales: "Pricing questions, plan comparisons, upgrades, purchasing for a team",
other: "Anything that does not fit the departments above",
},
),
},
});
const { choice: result, probabilities, confidence } = answers.department;
// Your code decides what to do with the answer.
if (confidence < 0.5) {
console.log("Unsure. Route to a person.", probabilities);
} else {
console.log("Route to " + result + " (confidence " + confidence.toFixed(2) + ")");
}Inputs and outputs
Request fields
- state
- The customer message, sent as a plain string.
- questions.department
- A Choice question. Each option key carries a one-line description that reaches the model.
Response fields
- choice
- The option with the highest probability.
- probabilities
- One value per option; the API documents that they sum to 1.
- confidence
- A 0–1 statistic TypeSafe derives from how concentrated or spread out the probabilities are — not a guarantee that the choice is correct.
The five departments and their descriptions above are exactly what the live demo and the message-routing recipe send — both descriptions and keys reach the model, so write them to distinguish the options from each other:
- billing
- Charges, invoices, refunds, payment methods, subscription costs
- account
- Login, password, profile, permissions, closing or changing an account
- technical
- Bugs, errors, outages, integrations, something not working
- sales
- Pricing questions, plan comparisons, upgrades, purchasing for a team
- other
- Anything that does not fit the departments above
Handling the result
The example branches on confidence: below 0.5 it treats the answer as unresolved and routes to a person; otherwise it acts on the chosen department. The 0.5 cutoff here is illustrative, not a value TypeSafe recommends universally — the official docs say a confidence threshold “is not one number” and should scale with the stakes of the action it gates, tuned against your own data. A destructive action deserves a higher bar than a read-only one.
Common errors
The HTTP API returns a JSON body describing what went wrong. The official SDKs retry 429 and 529 with backoff by default, so most callers using @typesafe-ai/sdk need no extra handling for those two.
- 401 Unauthorized
- Missing or invalid API key. Check the Authorization header.
- 422 Unprocessable Entity
- The request body failed validation — for example a missing field or malformed question.
- 429 Too Many Requests
- Rate limit exceeded. Back off and retry after a short delay.
- 529 Overloaded
- TypeSafe is temporarily overloaded. Retry after a short delay.
Limitations worth knowing
- Jev currently accepts text input only — no images, audio, or video.
- Confidence is a statistic TypeSafe computes from the shape of the probability distribution, not a guarantee that the chosen answer is correct. A flatter distribution means lower confidence; the exact formula is not published.
- Jev is not documented as deterministic. TypeSafe emphasizes consistency over identical repeat outputs, so treat any single answer as a judgment, not a fixed fact.
- Rate limits and model aliases (like
jev-latest) can change over time; pin a versioned model id if you need stable behavior across releases.
Sources and verification
- TypeSafe documentation
- HTTP API reference — request/response fields and the error table above.
- JavaScript/TypeScript SDK reference — the import and method shape used above.
- Confidence — how it is derived, and why thresholds scale with risk.
- @typesafe-ai/sdk on GitHub — pinned at v0.6.0 in this site's package.json.
Testing status: the example above is compiled by this site's TypeScript build against SDK 0.6.0 and its request shape was checked against the API reference in September 2026. Passing a type check confirms the code compiles against that SDK version — it is not the same as running it against the live API, which this guide has not done.