Guide

Jev Python Guide

The official TypeSafe Python SDK works against this site unchanged: install typesafe-sdk, point the base URL at jev-api.org, and call system_one with a jev-api.org key. This guide covers install, configuration, the three question types, reading answers, and the async client.

Updated

Install

The package is typesafe-sdk on PyPI and needs Python 3.10 or newer. The source lives at github.com/typesafe-ai/typesafe-sdk-python.

pip install typesafe-sdk
# or: uv add typesafe-sdk
# requires Python 3.10+

Configure the key and base URL

The SDK reads two environment variables. TYPESAFE_API_KEY takes a key from your jev-api.org dashboard — TypeSafe console keys do not work here — and TYPESAFE_BASE_URL must be https://jev-api.org so requests reach the TypeSafe-compatible /v1/systemone endpoint instead of api.typesafe.ai.

# .env — a key from your jev-api.org dashboard
TYPESAFE_API_KEY=jeva_...
TYPESAFE_BASE_URL=https://jev-api.org

You can also pass them inline as TypeSafeClient(api_key=..., base_url="https://jev-api.org"). The default model is jev-latest; override it with TYPESAFE_DEFAULT_MODEL or the model argument. The default timeout is 10 seconds.

First call: Noul, Choice and Score

client.system_one takes a state — string, object, or array — and a questions map built from the Noul, Choice and Score classes. Each call below returns in about the model's documented latency band of 70 to 500 ms and uses 1 credit on this site.

from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

with TypeSafeClient() as client:  # reads TYPESAFE_API_KEY and TYPESAFE_BASE_URL
    response = client.system_one(
        state={"document": "I was charged twice. Please fix this ASAP."},
        questions={
            "billing": Noul(instructions="Is this ticket about billing?"),
            "tone": Choice(
                instructions="What is the customer's tone?",
                criteria={"calm": None, "frustrated": None, "angry": None},
            ),
            "urgency": Score(
                instructions="How urgent is this ticket?",
                criteria=["can wait", "this week", "today"],
            ),
        },
    )

print(response.nouls["billing"].noul)      # 0.0 .. 1.0
print(response.choices["tone"].choice)     # winning option
print(response.scores["urgency"].score)    # fractional level

Reading answers

The response object exposes typed views: response.nouls, response.choices, and response.scores, keyed by your question ids. A Noul answer carries .noul, the probability of yes between 0 and 1. A Choice answer carries .choice, .probabilities and .confidence. A Score answer carries a fractional .score plus .legend, .probabilities and .confidence.

Use confidence as the handoff signal. When it is low or two options sit close together, route the case to a person or ask a narrower follow-up question instead of lowering the threshold blindly. You can also read the raw per-question object through response.answers["id"].

Async client

AsyncTypeSafeClient has the same interface with awaitable calls — useful inside FastAPI endpoints or workers that fan out several states at once.

from typesafe_sdk import AsyncTypeSafeClient, Noul

async with AsyncTypeSafeClient() as client:
    response = await client.system_one(
        state="I was charged twice for my subscription.",
        questions={"refund": Noul(instructions="Is the customer asking for money back?")},
    )
    print(response.answers["refund"])

Without the SDK: plain requests

If you do not want the dependency, POST the JSON body yourself. This site's simple endpoint /api/v1/decisions accepts the same state-plus-questions shape with model jev-1.13 and slightly tighter limits (1 to 6 questions, 2 to 8 Choice options).

import os
import requests

res = requests.post(
    "https://jev-api.org/api/v1/decisions",
    headers={"Authorization": f"Bearer {os.environ['JEV_API_KEY']}"},
    json={
        "model": "jev-1.13",
        "state": "I was charged twice for my subscription.",
        "questions": {
            "refund": {"type": "noul", "instructions": "Is the customer asking for money back?"}
        },
    },
    timeout=30,
)
print(res.json()["answers"]["refund"])

Errors and timeouts

jev-api.org returns JSON errors with a detail field. The codes you will see:

  • 401 — missing or rejected API key. Check the Authorization: Bearer header and that the key came from this site.
  • 402 — the key is valid but the balance cannot cover the call. Add credits on the pricing page.
  • 422 — the body failed validation, or the model rejected it (for example over the 64k/32k token limits). The message names the field.
  • 429 — rate limited. Back off and retry.
  • 502 — the decision service did not return answers. No credit is used.

FAQ

Can I use my TypeSafe console key with this site?

No. Keys are not interchangeable: TypeSafe keys work on api.typesafe.ai, and keys from the jev-api.org dashboard work here. Set TYPESAFE_API_KEY to a jev-api.org key and TYPESAFE_BASE_URL to https://jev-api.org.

Which endpoint does the SDK call on this site?

With base_url set to https://jev-api.org, the SDK posts to /v1/systemone — the TypeSafe-compatible endpoint, which accepts the full question set (up to 256 questions, 255 Choice options, structured instructions) and bills 1 credit per successful call.

Does the SDK retry automatically?

The TypeSafe SDK ships with a default retry policy for transient errors such as 429; you can override it through the client's retry option. Validation errors (422) should be fixed in the body, not retried.

What Python version do I need?

Python 3.10 or newer. Both sync (TypeSafeClient) and async (AsyncTypeSafeClient) clients are in the typesafe-sdk package.

How do I know which model version answered?

The response's model field always reports the versioned id that served the request — jev-1.13.0 today — even when you sent an alias like jev-latest.

Send the first decision

Create a key, set the two environment variables, and run the snippet above.