Skip to the experiment
Jev Guide

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.

message-routing.tsTypeScript
// 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) + ")");
}
Type-checked against @typesafe-ai/sdk 0.6.0 (pinned in package.json) · not executed against the live API by this guide

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

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.