Decisions (Jev)
Evaluate information with Jev, a decision model hosted by TypeSafe, through your MindsHub API key. Send a state and named questions; receive matching answers with probabilities and token usage.
New to this kind of model? Read Decision models for when to use it and how to interpret its answers.
Endpoint
POST https://api.mindshub.ai/v1/decisions
Send Authorization: Bearer $MINDSHUB_API_KEY and Content-Type: application/json. Get your key from the MindsHub console and keep it on your server, outside source control. See Authentication.
This is a MindsHub HTTP endpoint. You do not need a TypeSafe key or SDK. Chat SDK methods such as chat.completions.create() use a different request format; use an ordinary HTTP client for decisions.
Quick example
This example evaluates one delivery report in three ways: selects a team (choice), checks for an explicit replacement request (noul), and rates damage (score). Python uses only the standard library. The TypeScript example uses native fetch in Node.js 20+ and runs as an ES module.
Set MINDSHUB_API_KEY in your server environment, then run the example for your language. The same JSON body works in every HTTP client.
- Python
- TypeScript
- cURL
import json
import os
from urllib.error import HTTPError
from urllib.request import Request, urlopen
payload = {
"model": "jev",
"state": {"report": "The outer box arrived torn. The item inside is undamaged and works normally."},
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should review this delivery report?",
"criteria": {
"packaging": "Damage to the packaging, with the item itself intact.",
"product": "Damage to the item itself.",
"other": "A different issue, or not enough information to identify one.",
},
},
"replacement": {
"type": "noul",
"instructions": "Does the report explicitly ask for a replacement item?",
},
"damage": {
"type": "score",
"instructions": "How much damage does the report describe?",
"criteria": [
"Both packaging and item are undamaged.",
"Packaging is damaged; the item is intact and usable.",
"The item is damaged and cannot be used normally.",
],
},
},
}
request = Request(
"https://api.mindshub.ai/v1/decisions",
headers={"Authorization": f"Bearer {os.environ['MINDSHUB_API_KEY']}", "Content-Type": "application/json"},
data=json.dumps(payload).encode(),
)
try:
with urlopen(request, timeout=40) as response:
result = json.load(response)
except HTTPError as error:
raise SystemExit(f"HTTP {error.code}: {error.read().decode()}") from None
print(json.dumps(result, indent=2))
print("Team:", result["answers"]["team"]["choice"])
print("Replacement requested (probability):", result["answers"]["replacement"]["noul"])
print("Damage (0–2):", result["answers"]["damage"]["score"])
const apiKey = process.env.MINDSHUB_API_KEY;
if (!apiKey) throw new Error("Set MINDSHUB_API_KEY to your MindsHub API key.");
const response = await fetch("https://api.mindshub.ai/v1/decisions", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "jev",
state: { report: "The outer box arrived torn. The item inside is undamaged and works normally." },
questions: {
team: {
type: "choice",
instructions: "Which team should review this delivery report?",
criteria: {
packaging: "Damage to the packaging, with the item itself intact.",
product: "Damage to the item itself.",
other: "A different issue, or not enough information to identify one.",
},
},
replacement: {
type: "noul",
instructions: "Does the report explicitly ask for a replacement item?",
},
damage: {
type: "score",
instructions: "How much damage does the report describe?",
criteria: [
"Both packaging and item are undamaged.",
"Packaging is damaged; the item is intact and usable.",
"The item is damaged and cannot be used normally.",
],
},
},
}),
signal: AbortSignal.timeout(40_000),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const result = await response.json();
console.log(JSON.stringify(result, null, 2));
console.log("Team:", result.answers.team.choice);
console.log("Replacement requested (probability):", result.answers.replacement.noul);
console.log("Damage (0–2):", result.answers.damage.score);
curl --fail-with-body --max-time 40 https://api.mindshub.ai/v1/decisions \
-H "Authorization: Bearer $MINDSHUB_API_KEY" \
-H 'Content-Type: application/json' \
--data-raw '
{
"model": "jev",
"state": {
"report": "The outer box arrived torn. The item inside is undamaged and works normally."
},
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should review this delivery report?",
"criteria": {
"packaging": "Damage to the packaging, with the item itself intact.",
"product": "Damage to the item itself.",
"other": "A different issue, or not enough information to identify one."
}
},
"replacement": {
"type": "noul",
"instructions": "Does the report explicitly ask for a replacement item?"
},
"damage": {
"type": "score",
"instructions": "How much damage does the report describe?",
"criteria": [
"Both packaging and item are undamaged.",
"Packaging is damaged; the item is intact and usable.",
"The item is damaged and cannot be used normally."
]
}
}
}'
The response has the keys answers.team, answers.replacement, and answers.damage. For this report, expect the packaging team, a low probability of a replacement request, and a damage score close to 1. Exact probabilities and token counts can vary.
For a dev deployment, replace the URL with https://api.dev.mindshub.ai/v1/decisions and use a key for that environment. The examples above use the production address; a model must be activated in the environment's catalog before it can be called.
Request parameters
| Field | Type | Required | Meaning |
|---|---|---|---|
model | string | Yes | A MindsHub decision alias; see Models. |
state | string, object, or array | Yes | The information every question evaluates. Objects and arrays can contain nested JSON values. A top-level number, Boolean, or null is not a valid state. |
questions | object | Yes | A nonempty map of question names to question definitions. Each answer is returned under its question's name. |
questions.<name>.type | string | Yes | Exactly noul, choice, or score; determines the criteria and answer shape. |
questions.<name>.instructions | string, object, array, or null | No | The judgment to make. Use a clear sentence for your first integration. |
questions.<name>.criteria | Depends on type | Depends on type | See below. |
Criteria for each type
| Type | Criteria contract | Guidance |
|---|---|---|
noul | Optional object with optional true and false descriptions, or null. Each description may be a string, object, array, or null. | Define what yes and no mean when the instruction alone is ambiguous. |
choice | Required object mapping option names to descriptions. Each description may be a string, object, array, or null; the criteria object itself cannot be null. | Provide meaningful descriptions and an other option when appropriate. |
score | Required nonempty array. Each level is a string, object, or array; a level cannot be null. Positions start at 0. | Start with a few clearly distinct levels ordered along one dimension. |
For example, a noul can make its boundary explicit:
{
"type": "noul",
"instructions": "Does the customer explicitly request a replacement?",
"criteria": {
"true": "The customer asks for another item to be sent.",
"false": "The customer only describes a problem or asks for information."
}
}
Instructions are optional in the wire schema, but the question's name is not an instruction. Always supply the meaning in instructions, criteria, or both. Prefer complete descriptions to relying on a name such as urgent.
The gateway preserves omitted fields, explicit null values, and additional JSON fields when forwarding the request. TypeSafe applies its own semantic validation. Unknown fields are not a promise of additional capabilities: use the documented fields above. In particular, chat parameters such as messages, temperature, max_tokens, tools, and stream are not supported controls for this endpoint.
The generated endpoint reference contains the complete schemas. For interpretation and question design, see Decision models.
Response
One illustrative response to the complete quick example is shown below. Values are simplified for readability; do not assert exact numeric outputs in your application.
{
"model": "jev-1.13.0",
"answers": {
"team": {
"type": "choice",
"choice": "packaging",
"confidence": 1.0,
"probabilities": {"packaging": 1.0, "product": 0.0, "other": 0.0}
},
"replacement": {"type": "noul", "noul": 0.0},
"damage": {
"type": "score",
"score": 1.0,
"confidence": 1.0,
"legend": {
"0": "Both packaging and item are undamaged.",
"1": "Packaging is damaged; the item is intact and usable.",
"2": "The item is damaged and cannot be used normally."
},
"probabilities": {"0": 0.0, "1": 1.0, "2": 0.0}
}
},
"usage": {"input_tokens": 420, "output_tokens": 46}
}
| Field | How to use it |
|---|---|
model | The actual model version returned by TypeSafe. Record it when comparing results over time. |
answers | Map with the same names and question types as your request. Read by name, not object order. |
Noul: noul | Probability of yes, from 0 to 1. It is a number, not a Boolean. |
Choice: choice | The selected option name from your criteria. |
Choice/score: probabilities | Probabilities across the named choices or numbered levels. Allow small floating-point rounding differences when checking their sum. |
Choice/score: confidence | TypeSafe's certainty statistic from 0 to 1. It is not necessarily the highest option probability. |
Score: score | Probability-weighted mean of the level numbers, between 0 and the last index. May be fractional. |
Score: legend | Map from string indices to your original level descriptions. |
usage.input_tokens, usage.output_tokens | Provider-reported token counts for the whole request, not one counter per question. Both are present even while the price is zero. |
Models and versions
Send in model | Meaning |
|---|---|
jev | The Jev version adopted by MindsHub; currently jev-1.13.0. |
jev-latest | An accepted synonym for jev. Moves when MindsHub updates its catalog. |
jev-1.13.0 | The version pinned by this integration. Use it when evaluating changes against a fixed model. |
MindsHub's aliases advance through MindsHub catalog updates; a new TypeSafe release does not automatically change them. Pinning a version controls selection, not how long the provider will keep serving it.
Use GET /v1/models with the same key to discover catalog models. Jev entries have kind: "decision"; an accepted synonym need not have its own row. TypeSafe-only aliases such as jev-preview are not automatically MindsHub aliases.
Unlike the chat and embedding endpoints, the decisions response's model reports the served version rather than echoing the requested alias. For example, requesting jev currently returns jev-1.13.0.
Limits and billing
- Launch promotion: Jev input and output both cost $0 through MindsHub. An empty wallet is allowed, and requests do not consume the included allowance. Organization permissions and rate limits still apply. See Billing.
- Usage still exists: input and output token counts are returned and recorded during the promotion. Zero price does not mean zero tokens. Check the usage summary to reconcile your calls.
- Context: the current Jev model allows 64,000 tokens for state plus all questions, and 32,000 tokens for state plus the longest individual question. Both limits must be met; TypeSafe enforces them. See the provider's model limits.
- Several questions: include independent questions about the same state in one request. The state is shared, while the questions and their criteria still contribute input tokens. This is not a separate batch-jobs API.
- Request rate: MindsHub's rate limits and provider capacity apply. TypeSafe's direct-account limits are not a throughput entitlement for a MindsHub key.
Endpoint behavior
The call is synchronous: it returns one JSON response after evaluation. There is no SSE streaming, background polling, tool execution, or conversation chaining. Each request must contain all the state its questions need. No image, audio, or video input is supported.
MindsHub handles authentication, access, model selection, and usage accounting; TypeSafe serves Jev. Successful provider answers and usage are returned in their native JSON shape. The endpoint validates the response before returning it, so an invalid provider response can produce a 502 instead of partial answers.
Errors and retries
Check the HTTP status before reading answers. Errors may contain a MindsHub error object, a validation detail list, or TypeSafe's original body. The examples retain the error status and body rather than assuming one universal shape.
| Status | Typical cause | What to do |
|---|---|---|
400 | Wrong model kind, model not configured, or provider rejection | Inspect the code/message. Use a decision model and correct the request; report a configuration failure. |
401 / 403 | Invalid MindsHub key or insufficient access | Check the key, its environment, and organization permissions. |
404 | Alias absent from this environment's catalog or unavailable to this account | Check GET /v1/models on the same host with the same key. |
422 | Missing field, invalid question type/shape, or provider validation | Inspect the field error, fix the payload, and resend. |
429 / 529 | Rate limit or provider overload | Honor Retry-After when supplied; use bounded backoff. |
502 | Provider connection, credential, or response problem | Preserve the response for diagnosis. Check the retry caveat below before resending. |
503 | Access policy temporarily unavailable | Retry with bounded backoff. |
504 | Provider timeout | The evaluation may already have run; do not assume that resending is free of duplicate work. |
Provider validation, rate-limit, and overload errors keep their status and body, including Retry-After when supplied. A provider credential failure becomes a gateway 502; it does not mean your MindsHub key needs replacing. Other provider failures may retain their original status. See Errors for common MindsHub access failures.
The gateway may retry one explicit provider 429 or 529 refusal when the requested delay is at most one second. It does not automatically retry ambiguous timeouts or disconnects. There is no documented idempotency key for this endpoint: a repeated POST can execute another evaluation. Even during the free promotion, account for duplicate work and rate-limit use before adding client retries.
For support, retain the HTTP status, response body, any request ID in the response headers, requested model, and timestamp. Keep API keys out of logs and support messages.