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:

ModelSpecLimitsPriceEndpoint
TypeSafe Jev 1.13
typesafe/jev-1.13
32,000-token context · choice / noul / scoreup 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.

POST
/openrouter/decisions/jev-1-13

Ask 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.

Request
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" }
      }
    }
  }
Response (200)
{
  "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.

  • choicePick one of several options. `criteria` is an object of option name → description; the answer carries `choice`, per-option `probabilities` and a `confidence`.
  • noulA 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.
  • scoreA 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.