Decisions API
Use OpenGateway Decisions to turn a state into typed probability-based judgments—yes/no, choice, and score—without generating prose, with batched questions and optional media.
The Decisions API evaluates a state against named questions and returns structured answers: probabilities and selected values, not generated text. Use it when an application needs machine-readable judgments for classification, routing, moderation, rubric scoring, or gating an extraction. Use chat completions when you need generated text, a conversation, or an explanation.
The endpoint is POST https://apis.opengateway.ai/v1/decisions. Authenticate with Authorization: Bearer <key>. For the complete request and response schemas, see the Decisions API reference.
Choose between Decisions and chat#
Choose Decisions when you can describe the judgment with a question and want a typed result your code can consume directly. It returns no prose and does not stream. Use chat when you need free-form text, dialogue, or an answer that explains its reasoning in words.
Question types#
A request can contain different question types together. Each answer uses the question ID as its key in answers.
noul: probability of yes#
Use noul for a yes/no judgment. The answer's noul field is the probability of yes, from 0 to 1; there is no separate confidence field because this probability is the result. Use criteria.true and criteria.false to clarify what each outcome means when needed.
choice: argmax option#
Use choice when exactly one of your defined options should be selected. The answer's choice is the option with the highest probability (the argmax); probabilities gives the probability for each option, and confidence is the model's confidence value.
score: expected rubric level#
Use score for an ordered rubric. Put criteria in order from low to high. The answer's score is the probability-weighted expected level, so it can be fractional; legend maps each numeric level to its criterion text, probabilities gives the probability of each level, and confidence is the model's confidence value. For example, a score of 1.19 is an expectation between levels 1 and 2, not a selected label.
Write good instructions and criteria#
Write instructions as a direct, specific question about the decision you need. State how to interpret the relevant evidence and avoid combining unrelated judgments into one question. instructions may be a string, object, or array; use structured instructions when that makes the task clearer.
Use criteria to make boundaries explicit:
- For
noul, define what counts as true or false withcriteria.trueandcriteria.falsewhen a bare yes/no question could be ambiguous. - For
choice, provide at least two options incriteria, with a short description for each option (ornullwhen no description is needed). Make the options distinct and collectively cover the likely outcomes. - For
score, provide at least twocriteriadescriptions in low-to-high order. Keep the scale consistent and make each level distinguishable.
For noul, instructions is required; if it is blank, provide meaningful true/false criteria instead. Be precise about what the model should judge rather than asking it to produce an explanation.
Reference fields in state#
Pass the content to judge as state: a string or a JSON object/array. Preserve useful structure so a question can refer directly to a field. Use backtick paths in instructions, such as `ticket` or `support.tickets[0].message`, to point to a specific value in the state.
For example, with state: {"ticket":"I was charged twice."}, ask Which team should handle `ticket`? and define options such as billing and technical in criteria.
Batch up to 64 questions#
Send between 1 and 64 questions in one request. questions is a map from a non-blank question ID to its question object; the same state is evaluated for each question, and the IDs are returned as keys in answers. Batching is useful when an application needs several independent judgments about one item.
Images and video#
Use sionic-ai/jev-omni to judge images. Pass images as an array of base64-encoded or data-URL strings, with up to 8 images per request. Each media item is limited to 20 MiB and all media together to 32 MiB. jev-omni takes text, image, and video input; it does not take audio, and a request with audio is rejected. Video fields are available in the API schema, but this guide's examples cover images only.
For example, encode a local image file and include it in the request:
import base64from pathlib import Pathimage = base64.b64encode(Path("receipt.jpg").read_bytes()).decode("ascii")payload = {"model": "sionic-ai/jev-omni","state": {"document": "receipt"},"questions": {"has_total": {"type": "noul","instructions": "Does the image show a total amount?",}},"images": [image],}
A model that does not accept the submitted media returns 400. In particular, sionic-ai/decider-4b is text-only and does not accept media.
Choose a model#
sionic-ai/decider-4bis text-only and the fastest option for text judgments.sionic-ai/jev-omniis stronger and supports text and images; it also takes video, but not audio.
Check the model catalog or public GET /v1/models for current availability and modalities before choosing a model.
Billing and latency#
Decisions are billed on input tokens only; output_tokens is 0. Check the model catalog for current pricing rather than relying on a fixed price.
As an indication, one observed request with three questions took about 0.1s on sionic-ai/decider-4b and about 0.4s on sionic-ai/jev-omni. These are sample timings, not latency guarantees.
Use fallbacks#
Add explicit fallback model IDs in extra.fallbacks when a request may use another Decisions-capable model after a primary attempt fails:
{"extra": {"fallbacks": ["sionic-ai/jev-omni"]}}
Use a fallback that supports the request's input modalities. For the extension fields, see the API reference.
Handle errors#
400 Bad Request: invalid request fields, malformed questions, or media sent to a model that does not accept it. For example, achoicequestion needs at least two options.401 Unauthorized: the API key is missing or invalid. Send it as a Bearer token.
Example: judge a support ticket#
The examples use plain HTTP because the OpenAI SDK does not provide a Decisions method. The request asks three questions about one ticket and reads the typed answer map.
curl#
curl https://apis.opengateway.ai/v1/decisions \-H "Authorization: Bearer $OPENGATEWAY_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "sionic-ai/decider-4b","state": {"ticket": "I was charged twice for my subscription this month. Please refund the duplicate payment."},"questions": {"is_refund": {"type": "noul","instructions": "Is the customer asking for a refund?"},"category": {"type": "choice","instructions": "Which team should handle `ticket`?","criteria": {"billing": "Billing, payment, and subscription issues","technical": "Product problems and technical support","sales": "Purchasing and sales inquiries"}},"urgency": {"type": "score","instructions": "How urgent is `ticket`?","criteria": ["Not urgent", "Somewhat urgent", "Very urgent"]}}}'
Python requests#
import osimport requestspayload = {"model": "sionic-ai/decider-4b","state": {"ticket": "I was charged twice for my subscription this month. Please refund the duplicate payment."},"questions": {"is_refund": {"type": "noul","instructions": "Is the customer asking for a refund?",},"category": {"type": "choice","instructions": "Which team should handle `ticket`?","criteria": {"billing": "Billing, payment, and subscription issues","technical": "Product problems and technical support","sales": "Purchasing and sales inquiries",},},"urgency": {"type": "score","instructions": "How urgent is `ticket`?","criteria": ["Not urgent", "Somewhat urgent", "Very urgent"],},},}response = requests.post("https://apis.opengateway.ai/v1/decisions",headers={"Authorization": f"Bearer {os.environ['OPENGATEWAY_API_KEY']}"},json=payload,timeout=30,)response.raise_for_status()result = response.json()print(result["answers"]["category"]["choice"])
TypeScript fetch#
const payload = {model: "sionic-ai/decider-4b",state: {ticket:"I was charged twice for my subscription this month. Please refund the duplicate payment.",},questions: {is_refund: {type: "noul",instructions: "Is the customer asking for a refund?",},category: {type: "choice",instructions: "Which team should handle `ticket`?",criteria: {billing: "Billing, payment, and subscription issues",technical: "Product problems and technical support",sales: "Purchasing and sales inquiries",},},urgency: {type: "score",instructions: "How urgent is `ticket`?",criteria: ["Not urgent", "Somewhat urgent", "Very urgent"],},},};const response = await fetch("https://apis.opengateway.ai/v1/decisions", {method: "POST",headers: {Authorization: `Bearer ${process.env.OPENGATEWAY_API_KEY}`,"Content-Type": "application/json",},body: JSON.stringify(payload),});if (!response.ok) {throw new Error(`Decisions API returned ${response.status}: ${await response.text()}`);}const result = await response.json();console.log(result.answers.category.choice);
To include an image, change the model to sionic-ai/jev-omni and add a base64 or data-URL string to the request's images array.