Structured Decisions
Models that return a typed decision rather than prose. Send a state and a set of questions in one POST and get, per question, a choice, a true/false probability or a score. Built for classification, routing and guardrails — anything where the shape of the answer is known in advance. Responses are synchronous and billed at a flat price per request.
Models & pricing
Every model has its own endpoint and bills a flat price per accepted request. The limits (request body size and question count) are fixed server-side, and the flat price is set against them:
| Model | Spec | Limits | Price | Endpoint |
|---|---|---|---|---|
TypeSafe Jev 1.13 typesafe/jev-1.13 | 32,000-token context · choice / noul / score | up to 8,192 bytes · 16 questions | ¥0.1 / decision | /openrouter/decisions/jev-1-13 |
The endpoint decides the model. Omit `model` from the body, or send exactly the model id from the table.
/openrouter/decisions/jev-1-13Ask for a decision
`state` carries the material to decide on (a string, an object or an array); `questions` is an object keyed by question name. Each question has a `type` (choice / noul / score), `instructions` (what to decide) and `criteria` (what to decide it by). Answers come back under the same keys as the questions.
curl https://api.fastmetal.ai/openrouter/decisions/jev-1-13 \
-X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d {
"state": "Customer wrote: my order never arrived and I want a refund.",
"questions": {
"intent": {
"type": "choice",
"instructions": "What does the customer want?",
"criteria": {
"refund": "they want their money back",
"track_order": "they want to know where the order is",
"other": "anything else"
}
},
"is_angry": {
"type": "noul",
"instructions": "Is the customer expressing anger?",
"criteria": { "true": "hostile or frustrated tone", "false": "neutral or polite" }
}
}
}{
"id": "gen-dec-1789761592-hJ9ahabHqfnukm1bqQ4M",
"model": "typesafe/jev-1.13-20260917",
"answers": {
"intent": {
"type": "choice",
"choice": "refund",
"probabilities": { "refund": 1, "track_order": 0, "other": 0 },
"confidence": 1
},
"is_angry": { "type": "noul", "noul": 0.86 }
},
"usage": { "input_tokens": 347, "output_tokens": 39 }
}Question types
The three types can be mixed in one request. The shape of `criteria` depends on the type.
choice— Pick one of several options. `criteria` is an object of option name → description; the answer carries `choice`, per-option `probabilities` and a `confidence`.noul— A true/false judgement. `criteria` is an object keyed `true` and `false`; the answer's `noul` is the probability (0–1) that the answer is true.score— A graded score. `criteria` is an array describing the levels from lowest to highest, and `score` is returned on that array's index scale (0 to 2 for three levels, fractional). The answer carries `score`, a `legend` mapping each level to its description, per-level `probabilities` and a `confidence`.
Billing
- Each model's flat price is deducted from your key's balance once per accepted request (HTTP 200). The number of questions and the length of the body do not change it.
- Rejected requests (HTTP 4xx/5xx) are not billed. An oversized body, a field that is not allowed, or a malformed question comes back as HTTP 400.
- If you never received a response (timeout, dropped connection) the outcome is unknown. Decisions return in about a second, so wait briefly before retrying.
Limits
- Request body size and question count are fixed per model (see the table). Size is counted on the request as it is sent upstream — compact JSON, including the pinned model name. Anything larger is rejected with HTTP 400.
- The body may contain only `state`, `questions` and `model`.
- Decisions are rate-limited platform-wide; HTTP 429 means retry shortly.