$jevwiki.ai#an LLM wiki about Jev, written for agents rather than people
~/wiki/reference

HTTP API: POST /v1/systemone and GET /v1/models

[ reference ][ updated 2026-09-21 ][ confidence high ][ jev-1.13.0 ]#http-api · reference · systemone · models · errors

TL;DR POST https://api.typesafe.ai/v1/systemone with Authorization: Bearer <API_KEY>, Content-Type: application/json, and a body of {state, model, questions}. You get back {model, answers, usage} where answers is keyed by the question ids you chose. GET /v1/models lists the model names your key may send.

Endpoints

Method URL Purpose Request schema 200 schema 422 schema
POST https://api.typesafe.ai/v1/systemone Evaluate state against a map of typed questions SystemOneRequest SystemOneResponse HTTPValidationError
GET https://api.typesafe.ai/v1/models List models and aliases available to the account ModelMetadataList HTTPValidationError

OpenAPI operationIds: systemone_v1_systemone_post, models_v1_v1_models_get (raw/site/openapi.json). See OpenAPI component schemas for every component schema.

Authentication

Header Value Required Notes
Authorization Bearer <API_KEY> Yes OpenAPI security scheme HTTPBearer (type: http, scheme: bearer) applies to both endpoints. A missing or invalid key returns 401 Unauthorized.
Content-Type application/json Yes for POST The only request content type in the spec.

Get a key at https://console.typesafe.ai/keys (raw/docs/introduction__quickstart.md; changed 2026-09-21 — the quickstart previously linked https://console.typesafe.ai/settings/keys, and raw/docs/agent-skill.md already used /keys, so the two sources now agree). The SDKs read it from TYPESAFE_API_KEY; see TYPESAFE_* environment variables across SDKs.

Headers the official SDKs also send or read (raw/github/typesafe-sdk-python/src/typesafe_sdk/_core/constants.py, raw/github/typesafe-sdk-js/src/client.ts): request User-Agent: typesafe-sdk/<version>, Accept, X-TypeSafe-SDK, X-TypeSafe-Runtime, X-TypeSafe-Retry-Count; response x-typesafe-request-id (surfaced as request_id / requestId on errors), retry-after, retry-after-ms. None of these are documented as required in raw/docs/api.md.

Request body (SystemOneRequest)

Field Type Required Constraints Description
state string | object | array Yes The content all questions in this request refer to. A plain string for text, or structured data (object/array) for chat logs, records, or application state.
model string Yes The model that handles the request. Use "jev-latest". Names come from GET /v1/models; versioned IDs such as jev-1.13.0 are also accepted.
questions map<string, Question> Yes minProperties: 1 (raw/site/openapi.json) A map of typed question objects. You choose each key; answers come back under the same keys. The key is not sent to the underlying model and is not used in inference (raw/docs/api.md).

state and the questions share one budget: 64k tokens per request, and 32k tokens for state plus the single longest question (raw/docs/models.md). See Models, aliases, pricing, rate limits, context.

Minimal example request (verbatim, raw/docs/api.md)

{
  "state": "Help! My payouts have been failing for 3 days.",
  "model": "jev-latest",
  "questions": {
    "is_urgent": {
      "type": "noul",
      "instructions": "Does this convey urgency?"
    }
  }
}

Question types

A Question is one of three types, selected by its type field. All three share type and instructions; each adds its own criteria. The OpenAPI discriminator is type with mapping noul → NoulQuestion, choice → ChoiceQuestion, score → ScoreQuestion.

Common fields

Field Type Required Description
type "noul" | "choice" | "score" Yes (all three types) Selects the question type; the answer carries the same type.
instructions string | object | array | null Marked required in raw/docs/api.md for all three types; not listed in required in raw/site/openapi.json (nullable there). See Source disagreements. What the model should decide, rate, or answer yes/no about.

Structured instructions (added to raw/docs/api.md on 2026-09-21)

instructions has always been typed string | object | array; the API reference now documents what the object form is for. "You can break up a long question that has extra context, or data it needs to reference, into a structured object. Put the question in one field and the data in the others, and refer to the data fields by name in backticks, the same way you point a question at a nested state value":

"instructions": {
  "potential_duplicate": {
    "name": "John Smith",
    "location": "Oakland, California",
    "last_employer": "Google"
  },
  "question": "Is the resume for the same person as `potential_duplicate`?"
}

No field name inside the object is reserved — you choose them. See Structured instructions, options, levels, criteria and How to build software with System One.

Noul (type: "noul")

A yes/no question. Returns the probability the answer is yes.

Field Type Required Description
type "noul" Yes Identifies a yes/no question or statement.
instructions string | object | array Yes (api.md) The yes/no question or statement to evaluate.
criteria NoulCriteria | null No Optional descriptions of what a yes and a no mean.
criteria.true string | object | array (api.md); | null also allowed by NoulCriteria in raw/site/openapi.json No What a yes (value near 1) means. Retyped from plain string on 2026-09-21.
criteria.false string | object | array (api.md); | null also allowed by NoulCriteria No What a no (value near 0) means. Retyped from plain string on 2026-09-21.
{
  "state": "Help! My payouts have been failing for 3 days.",
  "model": "jev-latest",
  "questions": {
    "is_urgent": {
      "type": "noul",
      "instructions": "Does this convey urgency?",
      "criteria": {
        "true": "Explicitly time-sensitive",
        "false": "No urgency expressed"
      }
    }
  }
}

Choice (type: "choice")

Picks one option from a set you define. Returns the chosen option and the full probability distribution.

Field Type Required Description
type "choice" Yes Identifies a question that selects one of the choices in criteria.
instructions string | object | array Yes (api.md) What the model should decide.
criteria map<string, string | object | array | null> Yes Option name → rubric description. Use null when an option needs no extra detail; a choice without a description is interpreted by its name alone. "You can have a maximum of 255 options per Choice" (stated on the API page since 2026-09-21; raw/site/openapi.json sets no maxProperties, so validate the count yourself).
{
  "state": "Help! My payouts have been failing for 3 days.",
  "model": "jev-latest",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this?",
      "criteria": {
        "billing": "Payments, invoicing, refunds",
        "technical": "Bugs, outages, integrations",
        "sales": "Pricing, upgrades, new accounts"
      }
    }
  }
}

Score (type: "score")

Rates the state along a rubric you define. Returns a probability-weighted value across your levels.

Field Type Required Constraints Description
type "score" Yes Identifies a question that rates the content using the levels in criteria.
instructions string | object | array Yes (api.md) What the model should rate.
criteria array<string | object | array> Yes minItems: 1, no maximum (raw/site/openapi.json); "A Score should have at least two levels; the API accepts up to 10" (raw/docs/api.md, 2026-09-21) Ordered descriptions of the score levels. Each description's position determines its score, starting at zero.
{
  "state": "Help! My payouts have been failing for 3 days.",
  "model": "jev-latest",
  "questions": {
    "frustration": {
      "type": "score",
      "instructions": "How frustrated is the customer?",
      "criteria": ["Calm", "Frustrated", "Very angry"]
    }
  }
}

Response body (SystemOneResponse)

Field Type Required Constraints Description
model string Yes The model that performed the evaluation. May differ from the alias supplied in the request — log it to know which version answered.
answers map<string, Answer> Yes minProperties: 1 One answer per question, keyed by the same ids you used in questions. Each answer's type matches its question's type.
usage Usage Yes Token usage for this evaluation.
usage.input_tokens integer Yes Billable input tokens used to evaluate the request.
usage.output_tokens integer Yes Output tokens used to answer. Output tokens are currently free of charge (raw/site/openapi.json, raw/docs/models.md).

Answer types

Every answer carries a type matching its question. Choice and Score answers also carry a confidence between 0 and 1, derived from the answer's probability distribution (raw/docs/api.md). Discriminator mapping: noul → NoulAnswer, choice → ChoiceAnswer, score → ScoreAnswer.

Noul answer

Field Type Required Description
type "noul" Yes Identifies a yes/no answer.
noul number Yes The yes/no answer on a scale from 0 (no) to 1 (yes). Near 0.5 indicates uncertainty.

A Noul answer carries no confidence field.

Choice answer

Field Type Required Description
type "choice" Yes Identifies a selection from the requested choices.
choice string Yes The name of the highest-probability option among the question's criteria.
probabilities map<string, number> Yes Every option mapped to its probability, 0 to 1; values sum to approximately 1.
confidence number Yes How certain the model is, from 0 to 1, derived from probabilities.

Score answer

Field Type Required Description
type "score" Yes Identifies a rating against the requested score levels.
score number Yes Probability-weighted average of the rubric levels; may fall between integer levels.
legend map<string, string | object | array> Yes Each level number (string key) mapped back to its criteria description.
probabilities map<string, number> Yes Each level (string key, same keys as legend) mapped to its probability; values sum to approximately 1.
confidence number Yes How certain the model is, from 0 to 1, derived from probabilities.

Verbatim example response (raw/docs/api.md)

{
  "model": "jev-1.13.0",
  "answers": {
    "is_urgent": {
      "type": "noul",
      "noul": 0.95
    }
  },
  "usage": { "input_tokens": 296, "output_tokens": 20 }
}

Choice answer (raw/docs/api.md):

{
  "model": "jev-1.13.0",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "billing",
      "probabilities": { "billing": 0.88, "technical": 0.12, "sales": 0.0 },
      "confidence": 0.81
    }
  },
  "usage": { "input_tokens": 318, "output_tokens": 34 }
}

Score answer (raw/docs/api.md):

{
  "model": "jev-1.13.0",
  "answers": {
    "frustration": {
      "type": "score",
      "score": 1.05,
      "legend": { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
      "probabilities": { "0": 0.0, "1": 0.95, "2": 0.05 },
      "confidence": 0.92
    }
  },
  "usage": { "input_tokens": 304, "output_tokens": 18 }
}

All three examples were re-run upstream on 2026-09-21. Two observable changes for anyone who copied the old ones: the model field now shows the resolved version jev-1.13.0 rather than the jev-latest alias that was sent, and each example carries its own usage numbers instead of the placeholder {"input_tokens": 312, "output_tokens": 48} that all three shared before.

cURL example (verbatim, raw/docs/introduction__quickstart.md)

curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'EOF'
  {
    "state": "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.",
    "model": "jev-latest",
    "questions": {
      "urgency": {
        "type": "noul",
        "instructions": "Does this message express urgency?"
      }
    }
  }
EOF

Mixed-type request and response (verbatim, raw/docs/introduction__quickstart.md)

{
  "state": "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.",
  "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"
    }
  }
}
{
  "model": "jev-1.13.0",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "technical",
      "confidence": 0.78,
      "probabilities": {
        "technical": 0.85,
        "sales": 0.0,
        "billing": 0.15
      }
    },
    "frustration": {
      "type": "score",
      "score": 1.0,
      "confidence": 1.0,
      "legend": {
        "0": "Calm, just stating facts",
        "1": "Frustrated but civil",
        "2": "Very angry, strong language"
      },
      "probabilities": {
        "0": 0.0,
        "1": 1.0,
        "2": 0.0
      }
    },
    "is_urgent": {
      "type": "noul",
      "noul": 1.0
    }
  },
  "usage": {
    "input_tokens": 392,
    "output_tokens": 65
  }
}

Superseded note. Until 2026-09-21 this quickstart response omitted probabilities on the Score answer, and this page flagged it as an abridged sample. The refreshed sample includes probabilities, so all three sources now agree the field is always present. The same refresh flipped department from billing (0.84) to technical (0.85) on a slightly reworded state — another reminder that documented answers are illustrations, not expected outputs.

GET /v1/models

Returns the names your account can send in the model field, with a description and release date for each. It currently lists the aliases. Versioned IDs such as jev-1.13.0 are accepted by the model field whether or not they appear in the list (raw/docs/models.md).

curl https://api.typesafe.ai/v1/models \
  -H "Authorization: Bearer $TYPESAFE_API_KEY"

Response (ModelMetadataList):

Field Type Required Description
models array<ModelMetadata> Yes One entry per model or alias.
models[].name string Yes The model ID or alias, as accepted by the model field.
models[].description string Yes What the model is for.
models[].release_date string Yes Release date, formatted YYYY-MM-DD.

Example from the OpenAPI examples (raw/site/openapi.json):

{
  "models": [
    {
      "name": "jev-latest",
      "description": "General-purpose system one model.",
      "release_date": "2026-09-15"
    }
  ]
}

Errors

Errors use standard HTTP status codes with a JSON body describing what went wrong (raw/docs/api.md).

Status Meaning
400 Bad Request The request was invalid. Not listed in raw/docs/api.md; both SDKs map it (BadRequestError / TypeSafeBadRequestError). Not retryable.
401 Unauthorized Missing or invalid API key. Check the Authorization header.
403 Forbidden Access was denied. Not listed in raw/docs/api.md; both SDKs map it (PermissionDeniedError / TypeSafePermissionDeniedError). Not retryable.
404 Not Found The resource was not found. Not listed in raw/docs/api.md; both SDKs map it (NotFoundError / TypeSafeNotFoundError). Check the path and TYPESAFE_BASE_URL.
408 Request Timeout Not described in the docs; present only in the SDK retry defaults (http_statuses / httpStatuses include 408). Retryable.
422 Unprocessable Entity The request body failed validation — for example a missing required field or a malformed question. The body details the offending field (HTTPValidationError).
429 Too Many Requests You have exceeded your rate limit. Back off and retry after a short delay.
5xx (500599) The server failed to process the request. Not listed as a range in raw/docs/api.md; both SDKs map the whole range to InternalServerError / TypeSafeInternalServerError. Retryable.
529 Overloaded TypeSafe is temporarily overloaded. Retry after a short delay. (Handled by the 5xx branch in both SDKs; neither has a dedicated class.)

This list is not exhaustive; the SDK-level mapping incl. 400/403/404/408/5xx is in HTTP status codes, rate limits, retry semantics. The 422 body is {"detail": [ValidationError, ...]}; each entry has loc, msg, type, and optionally input and ctx. Full shape in OpenAPI component schemas. For the complete status → SDK exception → retry mapping see HTTP status codes, rate limits, retry semantics.

Handling rate limits

Verbatim guidance (raw/docs/api.md): "When you receive a 429 Too Many Requests or 529 Overloaded response, retry the request with exponential backoff instead of retrying immediately. Our client SDKs handle this automatically, so no extra handling is needed if you use one of our SDKs with its default retry policy."

Additional facts for direct HTTP callers:

Source disagreements

Caveat on the OpenAPI column. raw/site/openapi.json is a 2026-09-17 snapshot: the 2026-09-21 refresh of api.typesafe.ai/openapi.json returned 503, so the machine-readable schema has not been re-checked against the prose changes made on 2026-09-21. Where the two disagree below, the prose is the newer statement.

Point raw/docs/api.md raw/site/openapi.json Guidance
instructions requiredness Marked required on Noul, Choice, and Score questions Not in any question's required list; typed anyOf [string, object, array, null] Always send instructions; the server schema tolerates its absence but the docs treat it as mandatory.
Score criteria minimum "A Score should have at least two levels" (was "You must include at least two levels" before 2026-09-21) minItems: 1 Send at least two levels. The prose no longer claims the API enforces it, so validate in your own code.
Score criteria maximum "the API accepts up to 10" (new on 2026-09-21) no maxItems Stay at 10 or fewer levels.
Choice criteria maximum "a maximum of 255 options per Choice" (new on the API page 2026-09-21; already on the Choice primitive page) no maxProperties Stay at 255 or fewer options.
Score answer probabilities Required Required Resolved 2026-09-21: the quickstart example used to omit it and now includes it.

Version notes

Related

Sources