Move an existing TypeSafe Jev integration to the Decision Models Jev-compatible API: review configuration, test requests and switch traffic deliberately.
Jev is a product of TypeSafe AI; Decision Models is not affiliated with TypeSafe AI.
Save the current configuration and representative test cases. Check question types, options, images, answer parsing and retries. Keep the previous provider configuration available for a deliberate rollback.
Set the base URL and path
Use https://api.decisionmodels.io as the base URL and POST /v1/systemone for text. Remove an existing /v1 suffix if your client appends the path itself. Check the actual outgoing path.
Create a separate API key
Create a Decision Models key in the dashboard and send it as Authorization: Bearer. TypeSafe keys, balances and accounts do not transfer. Store the key in an environment variable.
Replace the model ID
Replace the TypeSafe model ID with an available Decision Models ID, such as s1-fast. Check GET /v1/models rather than carrying over a TypeSafe alias.
Choose the processing region explicitly
For example, set S1-Region: eu. Values are eu or global, subject to key permissions; without a header the key default applies. EU requests stay in the EU. Peer-to-Peer processing outside the EU requires worldwide-processing consent on the key. Review processing and contract terms.
Split questions to fit model limits
s1-pro accepts up to 3 text questions per request; s1-fast accepts 1 and s1-vision 1. Split additional questions yourself. The service does not silently split or discard them; excess questions return 400 request_limit_exceeded. Also check the token and option limits below.
Review question types and images
Keep state and the questions object keyed by question name. Use the criteria shapes below. For images, use s1-vision through POST /v1/multimodal with exactly one image in the images array. PNG, JPEG and WebP data URLs or public HTTPS URLs are supported, bounded to 4 MiB decoded and 2,000,000 pixels. The text examples below do not test image requests.
Read answers and usage accounting
Read results under answers by question name. Capture usage.input_tokens, usage.output_tokens, usage.decisions and the reported model_version. Token counts come from the model, including image positions for image requests. Use dashboard usage receipts for monetary amounts; do not convert characters into billable tokens.
Test errors, retries and rollback
Test invalid keys, insufficient credit, model limits, rate limits and timeouts. Use the error codes below. Evaluate results on your own cases and switch traffic after your acceptance checks. A local contract test does not establish model quality or production availability.
Question types and current input limits
noul: Yes/no question; the answer’s noul is the probability of true.
choice: criteria is an object with at least two stable option IDs. Read choice, confidence and probabilities.
score: criteria is an ordered array with at least two levels. score is the probability-weighted mean of zero-based level indices and can be fractional.
Model
Input tokens per question
Questions
Options
s1-fast
8,000
1
16
s1-pro
8,192
3
64
s1-vision
8,000
1
26
Each question includes its state, criteria and prompt template; s1-vision also counts image positions. Check the full input limits.
What changes when you migrate
Checked 27 October 2026. The dated Jev alternatives comparison and migration notes define the compatibility boundary: separate keys, model IDs, processing tiers, billing, limits, metadata and errors. Switching models requires your own output evaluation. Byte-for-byte compatibility is not claimed.
Our score rubrics require at least two levels; TypeSafe’s published schema also accepts a single level. Excess questions are a non-retryable error.
With Idempotency-Key, an ongoing request returns 202 in_progress. After settlement, or while settlement is uncertain, it returns 409 idempotency_replay_unavailable with a receipt and no second charge, but no stored answer. A confirmed failure with no answer and no charge permits retrying the same key and body. A different body under the same key returns 409 idempotency_conflict. Use a new key only for a deliberately new inference.
Tested text examples
Each file below was executed unchanged against an isolated local HTTP mock of our published contract. Checks covered method, path, Bearer authentication, S1-Region, JSON body and reading a simulated answer with usage and model_version. No production inference request was made.
Set DECISIONMODELS_API_KEY to your key. The optional DECISIONMODELS_BASE_URL can point at your local mock; otherwise the public API base is used. Python examples require Python 3.10 and the package version shown. The fetch example is JavaScript-compatible TypeScript, executed with Node.js 20.19.4.
LiteLLM strips the typesafe/ provider prefix; the mock received s1-fast. Only Ollama’s Python client was tested, not its CLI. Typed SDKs may discard extra metadata such as model_version; the direct HTTP examples preserve it.
curl 7.81.0
tested on 27 Oct 2026 against our published contract with curl 7.81.0
curl.sh
curl --fail-with-body --silent --show-error --max-time 15 \
"${DECISIONMODELS_BASE_URL:-https://api.decisionmodels.io}/v1/systemone" \
-H "Authorization: Bearer $DECISIONMODELS_API_KEY" \
-H 'Content-Type: application/json' \
-H 'S1-Region: eu' \
--data '{"model":"s1-fast","state":"Mia owns a red bicycle.","questions":{"color":{"type":"choice","instructions":"Which color is the bicycle?","criteria":{"red":null,"blue":null}}}}'
Python requests 2.32.5
tested on 27 Oct 2026 against our published contract with Python requests 2.32.5
requests.py
import os
import requests
base = os.environ.get("DECISIONMODELS_BASE_URL", "https://api.decisionmodels.io")
response = requests.post(
base + "/v1/systemone",
headers={
"Authorization": "Bearer " + os.environ["DECISIONMODELS_API_KEY"],
"S1-Region": "eu",
},
json={
"model": "s1-fast",
"state": "Mia owns a red bicycle.",
"questions": {"color": {
"type": "choice",
"instructions": "Which color is the bicycle?",
"criteria": {"red": None, "blue": None},
}},
},
timeout=15,
)
response.raise_for_status()
print(response.json())
Node.js fetch 20.19.4
tested on 27 Oct 2026 against our published contract with Node.js fetch 20.19.4
fetch.ts
// JavaScript-compatible TypeScript; native fetch in Node.js.
const base = process.env.DECISIONMODELS_BASE_URL ?? "https://api.decisionmodels.io";
const response = await fetch(`${base}/v1/systemone`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.DECISIONMODELS_API_KEY}`,
"Content-Type": "application/json",
"S1-Region": "eu",
},
body: JSON.stringify({
model: "s1-fast",
state: "Mia owns a red bicycle.",
questions: { color: {
type: "choice",
instructions: "Which color is the bicycle?",
criteria: { red: null, blue: null },
} },
}),
signal: AbortSignal.timeout(15000),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(await response.json());
LiteLLM 1.106.4
tested on 27 Oct 2026 against our published contract with LiteLLM 1.106.4
litellm.py
import os
import litellm
response = litellm.systemone(
model="typesafe/s1-fast",
api_base=os.environ.get("DECISIONMODELS_BASE_URL", "https://api.decisionmodels.io"),
api_key=os.environ["DECISIONMODELS_API_KEY"],
extra_headers={"S1-Region": "eu"},
state="Mia owns a red bicycle.",
questions={"color": {
"type": "choice",
"instructions": "Which color is the bicycle?",
"criteria": {"red": None, "blue": None},
}},
timeout=15,
)
print(response.model_dump())
Ollama Python 0.6.3
tested on 27 Oct 2026 against our published contract with Ollama Python 0.6.3
ollama.py
import os
from ollama import Client
client = Client(
host=os.environ.get("DECISIONMODELS_BASE_URL", "https://api.decisionmodels.io"),
headers={
"Authorization": "Bearer " + os.environ["DECISIONMODELS_API_KEY"],
"S1-Region": "eu",
},
timeout=15,
)
response = client.systemone(
model="s1-fast",
state="Mia owns a red bicycle.",
questions={"color": {
"type": "choice",
"instructions": "Which color is the bicycle?",
"criteria": {"red": None, "blue": None},
}},
)
print(response.model_dump())
Handle these codes explicitly; the full rules are in errors and retries.
400 invalid_request, request_limit_exceeded: Correct the schema or model limits; do not retry unchanged.
401 invalid_api_key, 402 insufficient_credit, 403 tier_not_allowed, 404 unknown_model: Correct the key, balance, tier permission or model selection.
413 payload_too_large, 422 unsupported_modality: Reduce input size or select a supported modality.
429 rate_limit_exceeded: Retry-After must be respected.
503 model_unavailable, capacity_limit, 504 inference_timeout: Check the documented wait and settlement status before retrying. EU requests never fail over outside the EU.
Next step
Review the full migration notes and your own test cases before moving production requests.