Decisions API
The Decisions API lets a model make typed decisions about a piece of content instead of generating text. You provide the content to evaluate and a set of questions, and the model returns a structured answer for each one: the probability of yes/no, a single pick from a list of options, or a score on a graded scale, along with per-option probabilities and a confidence value.
It is built for classification, routing, moderation, scoring, filtering, and any other case where your code needs to branch directly on the result. The model can only answer with the options and levels you define, never anything outside them, so there is no free-form text to parse.
When using a decision model for the first time, it is recommended to read the Jev guide first, which covers quick start, question design, response fields, and scenario examples. This page is the field-level reference.
Endpoints
All three endpoints serve the same models with the same pricing; they differ only in request and response format. Pick the one that matches your client:
Authentication works the same as the other endpoints: Authorization: Bearer <your OFOXAI_API_KEY>. Only non-streaming requests are supported; each request returns all answers synchronously.
Available models
For the full list of models that support this API, see the models page . Calling it with a regular chat model (such as openai/gpt-4o) returns endpoint_not_supported.
Unified format: /v1/decisions
Request parameters
Input format
input accepts three forms:
- Text: a single string.
"input": "Customer message: I was charged twice, nobody has answered my two emails, and I need a refund today." - Structured data: a JSON object, passed to the model as-is. Questions can reference field names in backticks, such as
`message`."input": { "ticket_id": 4812, "message": "I was charged twice.", "plan": "pro" } - Message array:
[{ "role", "content" }], wherecontentis a string or a list of content blocks. Onlyinput_textandinput_imageblocks are supported. Images only work with models that can read them. Jev does not read images; sending one returns 400.
Question object
Request examples
cURL
curl https://api.ofox.ai/v1/decisions \
-H "Authorization: Bearer $OFOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "typesafe/jev-latest",
"input": "Customer message: I was charged twice, nobody has answered my two emails, and I need a refund today.",
"questions": [
{ "type": "predicate", "name": "is_frustrated", "instructions": "Is the customer frustrated?" },
{
"type": "choice",
"name": "category",
"instructions": "Which category does this ticket belong to?",
"choices": [
{ "value": "billing", "description": "Charges and refunds" },
{ "value": "bug", "description": "Product issue" },
{ "value": "other", "description": "Other" }
]
},
{
"type": "score",
"name": "urgency",
"instructions": "How quickly does a human need to respond?",
"levels": [
{ "label": "low", "description": "Within a week is fine" },
{ "label": "medium", "description": "Should respond soon" },
{ "label": "high", "description": "Must respond today" }
]
}
]
}'Response format
{
"model": "typesafe/jev-latest",
"answers": [
{ "type": "predicate", "name": "is_frustrated", "probability": 0.97 },
{
"type": "choice",
"name": "category",
"choice": "billing",
"confidence": 1,
"probabilities": [
{ "value": "billing", "probability": 1 },
{ "value": "bug", "probability": 0 },
{ "value": "other", "probability": 0 }
]
},
{
"type": "score",
"name": "urgency",
"score": 2,
"confidence": 1,
"legend": { "0": "low: Within a week is fine", "1": "medium: Should respond soon", "2": "high: Must respond today" },
"probabilities": [
{ "value": 0, "label": "low", "probability": 0 },
{ "value": 1, "label": "medium", "probability": 0 },
{ "value": 2, "label": "high", "probability": 1 }
]
}
],
"usage": { "prompt_tokens": 407, "completion_tokens": 72, "total_tokens": 479 }
}answers maps one-to-one to questions, in the same order. Fields for each answer type:
TypeSafe native format: /typesafe/v1/systemone
Request and response formats match the official TypeSafe API , so you can use the TypeSafe SDK directly or migrate existing code. Compared with the unified format, the differences are:
curl https://api.ofox.ai/typesafe/v1/systemone \
-H "Authorization: Bearer $OFOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-latest",
"state": "Help! My payouts have been failing for 3 days.",
"questions": {
"is_urgent": { "type": "noul", "instructions": "Does this convey urgency?" },
"department": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Payments, invoicing, refunds",
"technical": "Bugs, outages, integrations",
"sales": "Pricing, upgrades"
}
},
"frustration": {
"type": "score",
"instructions": "How frustrated is the customer?",
"criteria": ["Calm", "Frustrated", "Very angry"]
}
}
}'{
"model": "typesafe/jev-latest",
"answers": {
"is_urgent": { "type": "noul", "noul": 0.95 },
"department": {
"type": "choice",
"choice": "billing",
"confidence": 0.85,
"probabilities": { "billing": 0.9, "technical": 0.1, "sales": 0 }
},
"frustration": {
"type": "score",
"score": 1.03,
"confidence": 0.95,
"legend": { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
"probabilities": { "0": 0, "1": 0.97, "2": 0.03 }
}
},
"usage": { "input_tokens": 399, "output_tokens": 73 }
}SDK integration
OpenAI SDK
The official OpenAI SDK provides client.decisions.create(). Point base_url at https://api.ofox.ai/v1 and use the unified format for the request body. See the Python tab above for an example. You need an SDK version that includes the Decisions API (tested with openai Python 3.31.0).
TypeSafe SDK
With the official TypeSafe SDK, set base_url to https://api.ofox.ai/typesafe and replace api_key with your OfoxAI API Key. The rest of your code stays the same:
Python
# pip install typesafe-sdk
import os
from typesafe_sdk import TypeSafeClient, Noul, Choice, Score
with TypeSafeClient(base_url="https://api.ofox.ai/typesafe", api_key=os.environ["OFOX_API_KEY"]) as client:
r = client.system_one(
model="jev-latest",
state={"message": "I was charged twice, nobody has answered my two emails, and I need a refund today."},
questions={
"urgent": Noul(instructions="Is the customer asking for this to be handled today?"),
"dept": Choice(
instructions="Which team should handle this?",
criteria={"billing": "Charges, invoices, refunds", "technical": "Bugs, integrations", "sales": "Pricing, upgrades"},
),
"anger": Score(instructions="How upset is the customer?", criteria=["Calm", "Upset but polite", "Very angry"]),
},
)
print(r.nouls["urgent"].noul) # 0.98
print(r.choices["dept"].choice) # billing
print(r.scores["anger"].score) # 1.56Probability and confidence
- Probability answers “what is the answer”:
probabilityandprobabilitiesare the model’s calibrated probabilities for each possible answer. - Confidence answers “should I trust this decision”:
confidenceis derived from the probability distribution and is higher when the distribution is more concentrated. If two options each sit at 0.5,choicestill returns one of them, butconfidencewill be low.
A common pattern is to set a threshold in your code: act automatically when confidence is high, and route to a human or a stronger model for review when it is low.
Pricing
Billing is per token; see the model page for rates. typesafe/jev-latest bills input tokens only; output is not billed (completion_tokens / output_tokens are still returned).
All questions in a request share the same input, so putting multiple questions in one request is much cheaper and faster than splitting them across separate calls.
Limits
Common errors
For other general errors, see Error handling.