Developer Dashboard

Decisions API reference ​

The Decisions API evaluates evidence and returns a typed answer: the probability that a statement is true, a choice from supplied categories, or a score against an ordered rubric. Use it for classification, request routing, relevance checks, and prioritization. It does not generate a conversation reply or a custom JSON object.

AvalAI exposes the OpenAI Decisions request schema at /v1/decisions for TYPESAFE AI's Jev models. The provider's native request format uses the separate SystemOne endpoint. These endpoints have different field names and response formats.

Live verification, 2026-10-23: the three-option classification request below and one shared-text request containing predicate, choice, and score questions returned HTTP 200 with typed answers on both jev-latest and jev-preview. This verifies the documented small text requests; broader input types, large request limits, boolean choices, cache behavior, and refusals were not established by these checks.

Endpoint and authentication ​

text
POST https://api.avalai.ir/v1/decisions

Send an AvalAI API key in Authorization: Bearer … and a JSON body with Content-Type: application/json. Read the key from AVALAI_API_KEY in your server environment; do not embed it in browser code or public source files. See authentication.

Models and pricing ​

AvalAI model IDCurrent routed version
jev-previewjev-1.13.0
jev-latestjev-1.14.0

Both aliases have the same AvalAI price: USD 0.042 per 1 million input tokens, USD 0.00 per 1 million cached input tokens, and USD 0.00 per 1 million output tokens. The aliases identify the routed versions listed above; keep the alias and request configuration in your evaluation records so you can compare behavior after a version change. See the provider page and pricing.

OpenAI's own model availability and pricing apply to OpenAI's service. They do not determine AvalAI's Jev routes or commercial terms. microsoft-decision-1 is a possible future addition and is not an available model in this release.

Request body ​

Live verification: the corrected request using choices returned HTTP 200 with both aliases on October 23, 2026. The live checks also covered the Predicate, Choice, and Score definitions below. An earlier request used the incorrect field options and returned HTTP 400; correcting that field resolved the failure. Native System One has been checked separately and uses a different response format.

FieldTypeRequiredMeaning
modelstringYesAn AvalAI decision model ID, such as jev-latest or jev-preview.
inputstring or arrayYesShared evidence that every question evaluates. The examples below use a text string.
questionsarray of question objectsYesThe independent questions to answer about that evidence.

In the upstream OpenAI schema, input also accepts an ordered array of messages, function calls and outputs, or custom tool calls and outputs. A tool output must identify its corresponding call with call_id. Within that upstream schema, user messages can contain text, images, and JSON; system and developer messages contain input text, and assistant messages contain output text or refusals.

That broader upstream schema is not a promise that every input type is supported by Jev through AvalAI. Start with shared text and validate any additional input type against your selected route. In particular, do not assume image inputs, input_json, tool history, streaming, prompt cache controls, or OpenAI's numeric limits are supported just because the endpoint uses the OpenAI schema. For native text or JSON context, see SystemOne.

Question fields ​

FieldTypeApplies toMeaning
typestringAll questionspredicate, choice, or score.
instructionsstringAll questionsThe condition, category-selection rule, or scoring instructions. Use this exact field name.
namestringAll questions, optionalIdentifies the question in the answer. Give each question a distinct name.
choicesarraychoiceThe allowed options, each with a value and an optional description.
levelsarrayscoreThe ordered rubric levels, each with a label and an optional description.

Use choices, not options, on /v1/decisions. Use instructions for each question. The native /v1/systemone endpoint uses criteria and a different request schema. Mixing the two formats can produce a 400 invalid-request response.

The upstream OpenAI reference allows 1–400 questions, 2–255 unique choices, and 2–10 score levels. These are OpenAI limits, not verified AvalAI Jev limits. Keep requests bounded and test the sizes your application requires.

Predicate ​

A predicate checks a single condition. Its answer contains probability, the estimate that the condition is true. Phrase the question around one observable property and define what counts as evidence.

json
{
  "type": "predicate",
  "name": "duplicate_charge",
  "instructions": "Does the customer report being charged more than once for the same order?"
}

Choice ​

A choice selects a supplied category. The upstream schema supports string or boolean value fields; a string and a boolean are distinct even if they look alike. The text examples use strings. Supply descriptions that distinguish overlapping categories and include an explicit fallback when categories do not cover all inputs.

json
{
  "type": "choice",
  "name": "department",
  "instructions": "Which department should handle this complaint?",
  "choices": [
    {
      "value": "billing",
      "description": "Payments, invoices, and refunds."
    },
    {
      "value": "technical",
      "description": "Problems using the product."
    },
    {
      "value": "shipping",
      "description": "Delivery and tracking."
    },
    {
      "value": "other",
      "description": "Requests outside these categories."
    }
  ]
}

Score ​

A score rates evidence against ordered levels. Arrange levels from lowest to highest and give adjacent levels distinct criteria. Level indices start at 0; the upstream score is their probability-weighted average, so it can fall between levels. It is not an arbitrary number range that you set with minimum or maximum.

json
{
  "type": "score",
  "name": "severity",
  "instructions": "How severe is this issue?",
  "levels": [
    {
      "label": "Cosmetic",
      "description": "Appearance only; no lost functionality."
    },
    {
      "label": "Workaround available",
      "description": "A task fails, but another way works."
    },
    {
      "label": "Fully blocked",
      "description": "A task fails with no workaround."
    }
  ]
}

Text classification example ​

The clients below send the same request to AvalAI. The Python example uses only the standard library. The JavaScript example requires Node.js 18 or later and runs on the server. Each sends a single bounded attempt so an invalid request is visible; use the retry policy for production traffic.

bash
curl --fail-with-body \
  --connect-timeout 10 --max-time 30 \
  https://api.avalai.ir/v1/decisions \
  -H "Authorization: Bearer $AVALAI_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary '{
    "model": "jev-latest",
    "input": "I was charged twice. Please help.",
    "questions": [{
      "type": "choice",
      "name": "route",
      "instructions": "Which team should handle this message?",
      "choices": [
        {"value": "billing", "description": "Payments or invoices"},
        {"value": "technical", "description": "Software or API problems"},
        {"value": "other", "description": "Anything else"}
      ]
    }]
  }'
python
import json
import os
from urllib.error import HTTPError
from urllib.request import Request, urlopen

payload = {
    "model": "jev-latest",
    "input": "I was charged twice. Please help.",
    "questions": [
        {
            "type": "choice",
            "name": "route",
            "instructions": "Which team should handle this message?",
            "choices": [
                {"value": "billing", "description": "Payments or invoices"},
                {"value": "technical", "description": "Software or API problems"},
                {"value": "other", "description": "Anything else"},
            ],
        }
    ],
}
request = Request(
    "https://api.avalai.ir/v1/decisions",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {os.environ['AVALAI_API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
try:
    with urlopen(request, timeout=30) as response:
        decision = json.load(response)
except HTTPError as error:
    print(f"HTTP {error.code}: {error.read().decode('utf-8', errors='replace')}")
    raise

print(json.dumps(decision, indent=2, ensure_ascii=False))
javascript
const apiKey = process.env.AVALAI_API_KEY;
if (!apiKey) throw new Error("AVALAI_API_KEY is required");

const payload = {
  model: "jev-latest",
  input: "I was charged twice. Please help.",
  questions: [{
    type: "choice",
    name: "route",
    instructions: "Which team should handle this message?",
    choices: [
      { value: "billing", description: "Payments or invoices" },
      { value: "technical", description: "Software or API problems" },
      { value: "other", description: "Anything else" },
    ],
  }],
};
const response = await fetch("https://api.avalai.ir/v1/decisions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(payload),
  signal: AbortSignal.timeout(30_000),
});
const text = await response.text();
if (!response.ok) throw new Error(`HTTP ${response.status}: ${text}`);
console.log(JSON.stringify(JSON.parse(text), null, 2));

To compare the preview route, change only model to jev-preview. To ask a predicate or score question, replace the question object with the corresponding example above and supply appropriate evidence in input.

Current official OpenAI SDKs document client.decisions.create(...), but availability depends on the installed SDK version and its types. Raw HTTP is a useful baseline when your SDK has no Decisions resource or restricts model identifiers. Do not send this body through chat.completions.create: /v1/decisions uses input and questions, not the Chat Completions messages format.

Response schema and interpretation ​

The verified AvalAI text responses contain model, answers, usage, and AvalAI's estimated_cost field. The checked answers follow question order and echo name. The upstream schema also permits an unnamed question with a null answer name; this variant was not tested. Read each answer's type before interpreting its fields.

Answer typeUpstream fieldsInterpretation
predicatename, probability, typeEstimated probability that the condition is true.
choicename, choice, probabilities, confidence, typeSelected supplied value, per-option probabilities, and a separate confidence value.
scorename, score, probabilities, confidence, typeWeighted level index, per-level probabilities, and a separate confidence value.
refusalname, typeIn the upstream schema, the model declined an individual question; other questions can still receive answers.

Complete captured AvalAI response to the three-option request above, using jev-latest, received on 2026-10-23 16:11:38 UTC (12:11:38 p.m. America/New_York). It returned HTTP 200 with avalai-request-id: 01a16988-37e0-7360-b61b-5d703e489cb4. The same request with jev-preview returned HTTP 200 at 16:11:48 UTC, with request ID 01a16988-5fcb-7101-b32e-5eebaed63b9b. Numeric answers, token counts, and currency conversion values can differ on future requests:

json
{
  "model": "jev-latest",
  "answers": [
    {
      "type": "choice",
      "name": "route",
      "choice": "billing",
      "probabilities": [
        {
          "value": "billing",
          "probability": 1.0
        },
        {
          "value": "technical",
          "probability": 0.0
        },
        {
          "value": "other",
          "probability": 0.0
        }
      ],
      "confidence": 1.0
    }
  ],
  "usage": {
    "input_tokens": 333,
    "input_tokens_details": {
      "cached_tokens": 0,
      "cache_write_tokens": 0
    },
    "output_tokens": 38,
    "output_tokens_details": {
      "reasoning_tokens": 0
    },
    "total_tokens": 371
  },
  "estimated_cost": {
    "unit": "0.0000139860",
    "irt": 3.78,
    "exchange_rate": 270000
  }
}

Choice probability entries use value and probability. Score probability entries additionally include label; their value is the zero-based level index. confidence is separate from the selected option's probability: do not replace one with the other or invent a formula from the returned probabilities. Do not assume that a provider's probability entries always contain every option.

The captured usage reports 333 input tokens and 38 output tokens, totaling 371. The cache-read, cache-write, and reasoning token counts are 0 in this capture. Zero output pricing does not mean zero reported output tokens.

The USD estimate is 333 × 0.042 / 1,000,000 = 0.0000139860, matching estimated_cost.unit; billing uses the priced input tokens here, not total_tokens. estimated_cost.irt is 3.78 at the captured exchange_rate of 270000. These are returned estimates from that request, not a fixed exchange rate or a promise of identical token accounting for other inputs. The presence of cache fields with zero values does not prove cache-hit or cache-write behavior.

Handle missing, malformed, unknown, or refused answers as unresolved decisions. A refusal is not a negative predicate or a fallback category. Refusal behavior and untested upstream response variants require additional route-specific verification through AvalAI.

Set thresholds with labeled examples from your application and the cost of incorrect routing. A high probability does not prove that a decision is correct. Send uncertain results to a review queue and keep the application action separate from the model answer. See the decision-model guide and Jev cookbook.

Multiple questions and workflow boundaries ​

Independent questions can share one input: for example, route a ticket and check whether it mentions a duplicate charge. A question cannot consume another question's answer in the same request. For a dependent workflow, read the first response and then build a separate request.

Decisions evaluates supplied evidence; your application executes the resulting route, filter, or review action. If you need extracted fields, a written explanation, or a custom output object, use a suitable Responses API model and structured output support instead.

Errors and retries ​

SymptomWhat to checkRetry policy
400 or invalid requestJSON syntax, model, input, questions, instructions, and choices/levels. Never replace choices with options or send native criteria here.Correct the request first. Repeating the same invalid body will not fix it.
401AvalAI key validity and the Bearer header.Correct authentication first.
403Account or key access to the selected route.Resolve access before retrying.
404The exact /v1/decisions URL and model ID.Correct the path or model selection first.
429Rate limiting versus exhausted credit or quota in the returned error body.Retry temporary throttling with a delay; credit or quota errors require account action.
500, 502, 503, or 504A temporary gateway or provider failure.Retry with a bounded policy; follow a valid Retry-After when present.
Network failure or timeoutConnectivity, per-attempt timeout, and whether the server may already have processed the request.Retry only within your overall deadline and attempt budget.

Follow a valid Retry-After delay as a minimum. When it is absent or invalid, use exponential backoff with jitter. Limit both attempts and total elapsed time; if the server requests a delay beyond your deadline, defer the work instead of retrying sooner. Account for SDK retries when adding your own retry loop. Retried requests may be processed and charged more than once; apply any downstream action only once using an application job ID.

For debugging, retain the endpoint, model alias, HTTP status, redacted error body, and response request identifiers described in response headers. Keep API keys and sensitive input out of shared logs. See error handling and rate limits.