Skip to content

Alternative installation methods: uv, npm, and direct curl to the API ​

The previous lesson walked through the main route with venv + pip, but TypeSafe SDK installation has more than one path: the official quick start also provides three alternative methods—uv, the JavaScript / TypeScript SDK, and direct Bash access. This lesson walks through all three—after 8 minutes, pick one based on your project.

What you'll be able to do after this lesson ​

  • Complete TypeSafe SDK installation with two uv commands, and lock dependencies into uv.lock
  • Install the Jev JavaScript SDK with npm (@typesafe-ai/sdk) and run the same ticket three-question example as the previous lesson
  • Run the same code directly with TypeScript (Node.js 22.18+)
  • Connect directly to the TypeSafe API with curl 7.76+, and see the raw JSON response in a single line
  • State the version requirements of each of the three routes and pick the one that fits your project

Your current dilemma ​

  • The project already uses uv; going back to venv + pip feels like a step backward
  • Our tech stack is all Node / TypeScript; setting up an entire Python environment for one API call isn't worth it
  • Haven't decided which SDK to use yet, and want to see what the API actually returns with curl before getting started

When to use this approach ​

When you need to:

  • Add Jev to a uv-managed Python project
  • Call Jev in a Node.js, frontend, or TypeScript project
  • Make direct HTTP calls in any language (to verify results first, or when there's no official SDK for your language)

And you don't want to:

  • Manually run python3 -m venv then pip install
  • Install an entire SDK just for one curl request

🎒 Preparation before starting ​

  • Completed Installation and your first request — this lesson reuses the same route_ticket.py example
  • A Key is in your environment variables: echo $TYPESAFE_API_KEY can print it in the terminal (if not, go back to Sign-up and API Key)
  • Prepare according to the route you'll take: Python 3.10+ (uv route), Node.js 22+ (npm route), curl 7.76+ (curl route)
  • Use Bash on the command line (macOS / Linux / Windows WSL — the official quick start commands are written for this environment)

Core idea ​

The "write code to send your first request" section of the official quick start provides four tabs: Python, JavaScript, TypeScript, and Bash. The previous lesson covered the Python venv + pip route; this lesson completes the rest.

Comparison of the three alternative routes:

RouteWhat gets installedVersion requirementsWho it's for
uvtypesafe-sdk (same package as pip)Python 3.10+, requires uv installedPython projects already using / wanting to use uv
npm@typesafe-ai/sdkNode.js 22+ (TS direct run 22.18+)Node, frontend, and TypeScript projects
curlNothing to installcurl 7.76+Any language; quick verification of API responses

All three routes call the same endpoint: POST https://api.typesafe.ai/v1/systemone, and authentication is always Authorization: Bearer <Key>. The only difference is "who wraps the HTTP for you".

The SDK does three things for you that you must do yourself with direct access:

TaskWhat the SDK doesWith direct curl
AuthenticationReads TYPESAFE_API_KEY automaticallyWrite -H "Authorization: Bearer $TYPESAFE_API_KEY" by hand
Rate-limit retries429 / 529 retries with exponential backoff by defaultWrite it yourself (the official errors page explicitly requires exponential backoff)
Request/response formatStatus and questions wrapped in classes, answers retrieved by IDBuild and parse the JSON yourself

Follow along ​

The three routes are independent of each other; just pick one based on your language (see the comparison table above); the step numbers are continuous for easy cross-referencing.

Step 1: Complete TypeSafe SDK installation with uv ​

Why: uv is an installation method listed alongside pip in the official quick start—two commands create the project + install the SDK, and it also automatically generates a cross-platform lockfile uv.lock.

First check whether uv is available:

bash
uv --version

If it isn't installed, use the official install script (macOS / Linux):

bash
curl -LsSf https://astral.sh/uv/install.sh | sh

Install the SDK. Run in the project directory:

bash
uv init --bare
uv add typesafe-sdk

You should see: neither command errors; the second outputs something like Installed 14 packages, with a line typesafe-sdk==0.7.5 in the list (the version number is whatever you installed). The directory now contains .venv/ and uv.lock, and the dependencies section of pyproject.toml gains "typesafe-sdk>=0.7.5".

  • The project directory now contains .venv/ and uv.lock

Run the example from the previous lesson—no need to activate any environment:

bash
uv run route_ticket.py

You should see: the exact same three lines as the previous lesson:

text
technical
0.67
0.99

route_ticket.py is the official example from the previous lesson; just copy it over as-is (the code is in Installation and your first request).

Three details about the uv route (based on the official uv documentation):

DetailExplanation
uv init --bareOnly generates pyproject.toml, without creating a src directory, README, or git—enough for a quick start
.venvuv manages the virtual environment alongside pyproject.toml; uv run automatically keeps it in sync with the lockfile. Using .venv/bin/python route_ticket.py directly also works
uv.lockLocks exact versions; the official recommendation is to put it under version control so the same set of dependencies can be reproduced on another machine

Step 2: Install the Jev JavaScript SDK with npm and get the example running ​

Why: The JavaScript / TypeScript SDK is one of the official two client SDKs, uses the same "state + questions" style as the Python SDK, and answer types can even be automatically inferred from the question definitions.

First check the Node version—there's an easy pitfall here:

bash
node --version

The JavaScript tab of the official quick start says "Node.js 20 or later," but that reflects an older version: the SDK documentation page and changelog both say Node.js 22 or newer (breaking change starting from v0.7.0), and the npm package's engines field is >=22. Go with 22+ (see the pitfall reminder below for details).

Install the SDK:

bash
npm install @typesafe-ai/sdk
npm pkg set type=module

The second command marks the project as an ES module—the official example uses import syntax, and without this setting Node will error on loading.

You should see: the first command outputs added 1 package; the directory now contains node_modules/, package.json, package-lock.json. package.json contains "@typesafe-ai/sdk": "^0.7.0", and after the second command runs there's also "type": "module".

Use an editor to create route_ticket.js and paste in the official example:

javascript
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";

const ticket = "Our API integration started returning 500 errors on every request about 20 minutes ago, and we can't process any customer orders until this is fixed.";

const client = new TypeSafeClient({ defaultModel: "jev-latest" }); // Reads TYPESAFE_API_KEY.
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);

Run it:

bash
node route_ticket.js

You should see: three lines of output, consistent with the Python route:

text
technical
0.67
0.99
  • node route_ticket.js printed technical / 0.67 / 0.99

Run directly with TypeScript (optional) ​

Save the same code as-is into route_ticket.ts (identical in content to route_ticket.js), then simply:

bash
node route_ticket.ts

You should see: the same three lines of output. This requires Node.js 22.18 or higher (which supports running TypeScript directly); moreover, the SDK infers answer types from your question definitions—the type of response.answers.department.choice is "billing" | "technical" | "sales", and editor autocompletion works right away.

Step 3: Call the TypeSafe API directly with curl ​

Why: The Bash example in the official quick start is precisely "a complete HTTP request without the SDK." Any language that can send HTTP (Go, Java, Rust...) can call Jev following this structure; it's also good for verifying the API response before deciding whether to install an SDK.

Use an editor to create route_ticket.sh and paste in the official example:

bash
#!/usr/bin/env bash
set -euo pipefail
: "${TYPESAFE_API_KEY:?Set TYPESAFE_API_KEY first.}"

curl --fail-with-body --silent --show-error \
  https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "state": "Our API integration started returning 500 errors on every request about 20 minutes ago, and we can't process any customer orders until this is fixed.",
  "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"
    }
  }
}
JSON

Run it:

bash
bash route_ticket.sh

You should see: one whole line of raw JSON—unlike the three values printed by the SDK route, this is the complete response, containing the confidence and probabilities of each answer, plus usage metering. The formatted full sample is in "Reading the Full Response" in the previous lesson; field meanings are not repeated here: Installation and the First Request.

If no key is set, the script intercepts it locally first: route_ticket.sh: line 3: TYPESAFE_API_KEY: Set TYPESAFE_API_KEY first.—that's the purpose of the guard on line 3 at the top, so an empty key isn't sent to the server for nothing.

  • bash route_ticket.sh printed one whole line of JSON containing "answers"

Two reminders for the curl route:

ItemExplanation
--fail-with-bodyRequires curl 7.76+: on HTTP errors the exit code is non-0, but the response body is still printed, making it easy to see what went wrong
429 / 529With the direct-connection approach you have to write your own exponential backoff retries (the SDK includes them by default); if you receive one, take a look at the response body, wait a bit, and send again

Checkpoint ✅ ​

  • uv route: all three of .venv/, uv.lock, pyproject.toml are present, and uv run route_ticket.py outputs three lines of answers
  • npm route: package.json contains both "@typesafe-ai/sdk" and "type": "module"
  • curl route: bash route_ticket.sh outputs one whole line of JSON containing answers
  • I know all three routes call the same endpoint: POST /v1/systemone
  • I know the version requirements: Python 3.10+ / Node 22+ (direct TS run 22.18+) / curl 7.76+

Pitfall Reminders ​

❌ npm pkg set type=module reports npm error code ENOENT ​

Symptom: running npm pkg set type=module directly in an empty directory reports Could not read package.json ... no such file or directory.

Cause: npm pkg set is a command that modifies package.json, and it will not create the file for you if it doesn't exist in the directory yet (verified with npm 10.9.7).

Correct approach: follow the official order—first npm install @typesafe-ai/sdk (npm will generate package.json automatically), then npm pkg set type=module.

❌ node reports Warning: Failed to load the ES module ​

Symptom: run node route_ticket.js, and it reports Failed to load the ES module: route_ticket.js. Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension.

Cause: the project is not marked as an ES module (or was set to commonjs), while the official example uses import syntax.

Correct approach: npm pkg set type=module; or, following the error message's hint, rename the file extension to .mjs.

❌ You set up the environment per "Node 20+", but installed the new SDK version that requires 22+ ​

Cause: the official quickstart page's JavaScript tab says "Node.js 20 or later", but the SDK's current latest version on npm (0.7.0) has an engines of node >=22, and the changelog for v0.7.0 explicitly lists a breaking change: "require Node.js 22 or newer". Historically, only 0.5.7 / 0.6.0 supported 20+—the quickstart sentence refers to the old versions.

Correct approach: check first with node --version; if it's below 22, upgrade Node, or switch to this lesson's uv or curl route.

❌ After uv add, running python route_ticket.py still gives ModuleNotFoundError ​

Cause: the python in your system is not the environment managed by uv; the SDK was installed in the project's .venv.

Correct approach: follow the official example and consistently use uv run route_ticket.py (it first ensures .venv is in sync with the lockfile); or explicitly specify .venv/bin/python route_ticket.py.

Advanced tips (optional) ​

The SDK also handles compression for you. The Python SDK uses zstd to compress request bodies by default starting from v0.7.5; the JavaScript SDK automatically compresses request bodies over 1 KiB on Node 22.15+, and you can pass compression: false to disable it. Python 3.13 and earlier require explicitly adding extras: uv add "typesafe-sdk[zstd]" (there are also http2 and pil extras).

Languages without an official SDK. Go, Java, Rust… just send POST /v1/systemone following the structure from step 3; the field definitions for state / questions / answers are in the API quick reference.

Before taking the direct-connection route to production. Wrap exponential backoff retries for 429 / 529 into your HTTP client—this is an explicit requirement from the official errors page for direct-connection users; the SDK route doesn't need to worry about this.

Lesson summary ​

✅ uv route: uv init --bare + uv add typesafe-sdk, two commands to complete the TypeSafe SDK installation, then run directly with uv run.

✅ npm route: npm install @typesafe-ai/sdk + npm pkg set type=module, getting the same example running in both JavaScript and TypeScript (runs directly on 22.18+).

✅ curl route: --fail-with-body connects directly to the API, showing the full raw JSON with confidence and probabilities.

Key configuration fields recap:

FieldRecommended valueDescription
Python package nametypesafe-sdkSame package for pip / uv; uv add typesafe-sdk
JS package name@typesafe-ai/sdkInstall via npm; requires Node 22+ starting from v0.7.0
ES moduletype=moduleOfficial JS / TS examples use import, so this must be set
EndpointPOST https://api.typesafe.ai/v1/systemoneShared by all three routes
AuthenticationAuthorization: Bearer <Key>Added automatically by the SDK; curl uses $TYPESAFE_API_KEY
Environment variableTYPESAFE_API_KEYShared by all three routes; no keys written in code

Next lesson preview ​

All three routes are working, and there's one final safety net left: What to do when installation or running fails: initial troubleshooting.

You will learn:

  • How to pinpoint whether the environment, key, or network is the problem in 60 seconds using 3 commands
  • What the 400 / 401 / 413 / 422 / 429 status codes each mean and how to handle them
  • Which errors the SDK retries automatically (429 / 529), and how to write it yourself when connecting directly
  • How to include the request_id and minimal reproduction code when asking about an error