DocsAPI reference
Jev: TypeSafe System One
Run TypeSafe's Jev through INFRO with POST /v1/systemone: TypeSafe's body and model names, your TypeSafe account, spend limits and a cost per decision.
INFRO is in private early access. Running these examples requires an early-access account, an active trial or subscription entitlement, and your own provider connection. Self-serve purchasing is not generally open. See Early access.
Jev, TypeSafe's System One model, answers typed questions about a state — yes or no (noul), one of several options (choice), a level on a scale (score) — with probabilities, and writes no text. INFRO serves TypeSafe's endpoint at the same path, with the same request body and model names, so code written for TypeSafe points at INFRO by changing its base URL and its key.
Every request runs on your own TypeSafe connection, under your TypeSafe key, and TypeSafe bills your account for it. INFRO estimates what TypeSafe will charge and takes 0% markup on model spend; what INFRO charges is your subscription. The same endpoint serves every other decision model you connect — OpenAI's GPT-6 Luna, Cloudflare's Clef and the rest — on your own account with its provider.
Jev through INFRO
- Connect your TypeSafe key under Providers (TypeSafe issues it at console.typesafe.ai/keys). It is tested before it is saved, stored encrypted, and sent only to TypeSafe.
- Create an INFRO gateway key under Keys. To keep it to Jev, limit it to TypeSafe in the key's providers.
- Send requests to
https://api.infro.io/v1/systemonewith the gateway key as the bearer token. With TypeSafe's SDK, point it at INFRO's API host in place of TypeSafe's (api.infro.ioforapi.typesafe.ai) and give it the gateway key where it takes the TypeSafe key. - Name the model: a pinned version (
jev-1.13.0, as TypeSafe advises), a moving name (jev-latest,jev-preview) or the catalog idtypesafe/jev-1.13. Each response'smodelis the version that answered. - Read
usage.coston each response: the estimated TypeSafe charge for that decision. - Set a spend limit on the organization, a project, the key or a member under Budgets. It is checked before TypeSafe is called.
- Find each decision in the request log by the response's
id. Sendmetadata(for example{"workflow": "support-triage"}) to group decisions by workflow in usage, beside the LLM calls the same workflow makes.
curl https://api.infro.io/v1/systemone \
-H "Authorization: Bearer $INFRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-1.13.0",
"state": "My order arrived broken and I want my money back.",
"questions": {
"intent": {
"type": "choice",
"instructions": "The primary intent of this customer message",
"criteria": { "order_status": null, "return_refund": null, "complaint": null }
},
"urgent": { "type": "noul", "instructions": "Does this need a reply today?" }
},
"metadata": { "workflow": "support-triage" }
}'Model names
| You send | Sent to TypeSafe as | Estimated as |
|---|---|---|
jev-1.13.0 or typesafe/jev-1.13 | jev-1.13.0 | Jev 1.13 |
jev-latest or jev-preview, with or without typesafe/ | As typed | The version TypeSafe reports having served |
| A route's slug | The route's target | The target's model |
A moving name follows TypeSafe's releases: jev-latest is TypeSafe's latest stable release and jev-preview its latest release, both jev-1.13.0 when TypeSafe's models page was read on 6 October 2026. The version that answers can therefore change without a deploy on your side. The response's model and the request log name it, and the estimate is priced as that version. A version INFRO's catalog does not carry yet is recorded as unpriced — cost: null, never $0 — until it is added.
Request body
modelstringrequired- A Jev version, a moving name, the catalog id or a route. See Model names.
statestring | object | arrayrequired- What the questions are about. TypeSafe reads it once for every question.
questionsobjectrequired- Your question ids mapped to questions; the answers come back under the same ids, which are not sent to the model. INFRO accepts 1 to 1,000 per request.
| type | Fields | Answer |
|---|---|---|
noul | instructions; optional criteria.true and criteria.false | noul: the probability of yes |
choice | instructions; criteria: up to 255 options | choice, probabilities, confidence |
score | instructions; criteria: 2 to 10 levels | score, legend, probabilities, confidence |
INFRO checks the envelope — a state, between 1 and 1,000 questions, each with a known type — and leaves the rest of each question to TypeSafe, which validates it. TypeSafe's own limits apply: 64k tokens per request, with the state and the longest question within 32k, and rate limits TypeSafe adjusts as demand changes (docs.typesafe.ai/models, read 6 October 2026).
INFRO extensions
metadataobject- Recorded on the request and not sent to TypeSafe. Group usage and the request log by it.
loggingbooleanfalsekeeps this request's state and answers out of the request log, even when your organization turned prompt logging on.fallbacksstring[]- Other Jev models or routes to try when every TypeSafe connection for
modelfails.
X-INFRO-User-Id names your end customer for end-customer caps, and the cost attribution headers work as on every endpoint.
Response
{
"id": "req_…",
"model": "jev-1.13.0",
"answers": {
"intent": {
"type": "choice",
"choice": "return_refund",
"probabilities": { "order_status": 0.03, "return_refund": 0.94, "complaint": 0.03 },
"confidence": 0.91
},
"urgent": { "type": "noul", "noul": 0.72 }
},
"usage": { "input_tokens": 1000, "output_tokens": 0, "cost": 0.000042, "price_source": "list" },
"route": "primary",
"route_name": null,
"provider": "typesafe",
"connection": "conn_…"
}idstring- The request id, also in
X-INFRO-Request-Id. Look the decision up withGET /v1/requests/{id}. modelstring- The versioned model TypeSafe reports having served.
answersobject- TypeSafe's answers, unchanged, under your question ids.
usage.input_tokensinteger- As TypeSafe reports them.
usage.output_tokensinteger- As TypeSafe reports them. Output is free on Jev.
usage.costnumber | null- The estimated TypeSafe charge in US dollars, at TypeSafe's list rate or the rate you entered for your organization.
nullwhen it cannot be priced: a version the catalog does not carry, or no token counts reported. usage.price_sourcestringlist,customorcustom_provider. Absent whencostisnull.route, route_namestring | nullprimarywhen the first connection tried served it,standby_aand on when a later one did;route_nameis the route's slug whenmodelnamed one.provider, connectionstringtypesafeand the id of the TypeSafe connection that served it.
Before TypeSafe is called
- The key: its project, environment, IP allowlist, model allowlist and providers. A key limited to other providers gets
503 connection_out_of_scope. - Spend limits: the request's size in bytes — never fewer than its tokens — is reserved at the Jev rate against every blocking limit that applies: organization, project, key, member and end customer. Over one, the request is refused with a 402, and TypeSafe is not called.
- The key's rate limit, and your organization's guardrail setting for endpoints guardrails cannot read (below).
Several TypeSafe keys
With several TypeSafe keys connected, requests are spread across them. A key TypeSafe refuses (401, 403), a model the key cannot name (404) or a key over its rate limit (429) passes the request to the next key, then to fallbacks. A request TypeSafe rejects as invalid (400 or 422) is not retried: every TypeSafe key validates it the same way. Only connections whose provider answers decisions serve this endpoint: TypeSafe, and the providers of the other decision models — an OpenRouter connection on OpenRouter's own System One endpoint, never on its chat completions.
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | The envelope is wrong, or TypeSafe rejected the request: the message carries TypeSafe's words and the field it named (param: …). |
| 402 | budget_exceeded | A blocking spend limit. TypeSafe was not called. |
| 403 | model_not_allowed, guardrail_blocked | The key's allowlist excludes the model, or your guardrails refuse endpoints they cannot read. |
| 404 | model_not_found | A vendor/model id no provider names. |
| 429 | rate_limit_exceeded, provider_rate_limited | The key's rate limit, or every TypeSafe key is over TypeSafe's (with TypeSafe's Retry-After). |
| 502 | upstream_error | Every TypeSafe connection failed. |
| 503 | no_provider_connected, connection_out_of_scope | No connection serves the model (for Jev, TypeSafe or OpenRouter), or the key may not use the provider that does. |
The full list is on Errors.
Compatibility notes
- The key changes: send an INFRO gateway key, not the TypeSafe key, which stays in your INFRO connection.
- Responses add
id,usage.cost,usage.price_source,route,route_name,providerandconnectionto TypeSafe's fields. - Errors use INFRO's error envelope (
error.message,error.type,error.code) rather than TypeSafe's validation body; the field TypeSafe named is in the message. - Guardrails inspect chat completions only and do not read these requests. A guardrail policy set to block endpoints it cannot inspect refuses them with
403 guardrail_blocked. - The state and the answers are stored only when your organization turned on prompt logging and the request did not send
logging: false. - The console Playground does not run System One requests yet; decision policies have their own Try it panel.
Use decisions when the question, its thresholds and its fallback should live in a policy rather than in your code.