Decisions
Decision models answer typed questions about a piece of content instead of generating text. You send the content to judge and a set of questions; the model returns one typed answer per question, with real probabilities, in a single fast call.
Use them wherever your code has to make a decision: routing a support ticket, flagging a message, grading an answer, checking a photo, or deciding whether an agent should take an action.
Decision models are not chat models. They are served on two endpoints that share the same models, the same billing and the same answers, in two wire shapes:
| Endpoint | Shape | Use it with |
|---|---|---|
POST https://backend.sovereigneg.com/v1/decisions | OpenAI Decisions API | The OpenAI SDKs' client.decisions.create, SovereignEG's seg-sdk, or any OpenAI-style HTTP client |
POST https://backend.sovereigneg.com/v1/systemone | TypeSafe System One | The TypeSafe SDK, or clients already written against System One |
Pick the one that matches the client you already have. Both authenticate with your SovereignEG API key: Authorization: Bearer sk-....
Question types
Every question has instructions (what to judge). The three types, and what they are called on each endpoint:
| Asks | /v1/decisions type | /v1/systemone type | Answer |
|---|---|---|---|
| A yes/no question | predicate | noul | Probability the answer is yes, from 0 to 1 |
| Pick one option | choice | choice | The most likely option, plus every option's probability and a confidence |
| Rate on an ordered rubric | score | score | A probability-weighted level, plus every level's probability and a confidence |
A choice question takes 2 to 255 options. A score question takes 2 to 10 levels, lowest first.
Because the answers are probabilities, you pick the threshold: act automatically above 0.9, send to a human between 0.5 and 0.9, and so on.
Images
Decision models whose catalog entry lists image under input_modalities also judge pictures. Images are sent inline as base64 data URLs; hosted image URLs are not fetched. A model whose input_modalities lists only text refuses a request that carries images with 400 unsupported_input before the request reaches the provider. Check input_modalities on the model's entry in GET https://backend.sovereigneg.com/v1/models.
How to attach an image on each endpoint is shown below.
/v1/decisions
POST https://backend.sovereigneg.com/v1/decisions
Request
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Decision model ID (see Available models) |
input | string / array | Yes | The content to evaluate: plain text, or a list of user messages whose content is text or a list of input_text and input_image parts |
questions | array | Yes | Ordered questions. Each has type, instructions and an optional name that is echoed back; choice questions carry choices (value, optional description), score questions carry levels (label, optional description) |
safety_identifier | string | No | A stable identifier for your end user, for abuse tracking |
Example
from openai import OpenAI
client = OpenAI(api_key="sk-...", base_url="https://backend.sovereigneg.com/v1")
decision = client.decisions.create(
model="jev-1.13",
input="I paid for my order twice and it still has not arrived after a week.",
questions=[
{"type": "predicate", "name": "refund",
"instructions": "Is the customer asking for money back?"},
{"type": "choice", "name": "team",
"instructions": "Which team should handle this?",
"choices": [
{"value": "billing", "description": "Charges, refunds, invoices"},
{"value": "shipping", "description": "Delivery and tracking"},
{"value": "technical", "description": "Bugs and outages"},
]},
{"type": "score", "name": "urgency",
"instructions": "How urgent is this?",
"levels": [{"label": "Can wait"}, {"label": "Handle today"}, {"label": "Handle now"}]},
],
)
refund, team, urgency = decision.answers
if refund.probability > 0.8:
route_to(team.choice)SovereignEG's own Python SDK makes the same call with from seg import SEG and no base URL to set: seg-sdk on PyPI.
import OpenAI from 'openai'
const client = new OpenAI({ apiKey: process.env.SOVEREIGNEG_API_KEY, baseURL: 'https://backend.sovereigneg.com/v1' })
const decision = await client.decisions.create({
model: 'jev-1.13',
input: 'I paid for my order twice and it still has not arrived after a week.',
questions: [
{ type: 'predicate', name: 'refund', instructions: 'Is the customer asking for money back?' },
{
type: 'choice',
name: 'team',
instructions: 'Which team should handle this?',
choices: [
{ value: 'billing', description: 'Charges, refunds, invoices' },
{ value: 'shipping', description: 'Delivery and tracking' },
{ value: 'technical', description: 'Bugs and outages' },
],
},
],
})
const [refund, team] = decision.answers
if (refund.type === 'predicate' && refund.probability > 0.8) routeTo(team.choice)curl https://backend.sovereigneg.com/v1/decisions \
-H "Authorization: Bearer $SOVEREIGNEG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-1.13",
"input": "I paid for my order twice and it still has not arrived after a week.",
"questions": [
{ "type": "predicate", "name": "refund", "instructions": "Is the customer asking for money back?" },
{ "type": "choice", "name": "team", "instructions": "Which team should handle this?",
"choices": [
{ "value": "billing", "description": "Charges, refunds, invoices" },
{ "value": "shipping", "description": "Delivery and tracking" },
{ "value": "technical", "description": "Bugs and outages" }
] },
{ "type": "score", "name": "urgency", "instructions": "How urgent is this?",
"levels": [ { "label": "Can wait" }, { "label": "Handle today" }, { "label": "Handle now" } ] }
]
}'With an image, send input as messages:
"input": [
{
"role": "user",
"content": [
{ "type": "input_text", "text": "Photo the courier sent on delivery." },
{ "type": "input_image", "image_url": "data:image/jpeg;base64,..." }
]
}
]Response
One answer per question, in the order you asked, with your name echoed back:
{
"object": "decision",
"model": "jev-1.13",
"answers": [
{ "type": "predicate", "name": "refund", "probability": 0.96 },
{
"type": "choice",
"name": "team",
"choice": "billing",
"confidence": 0.75,
"probabilities": [
{ "value": "billing", "probability": 0.84 },
{ "value": "shipping", "probability": 0.14 },
{ "value": "technical", "probability": 0.02 }
]
},
{
"type": "score",
"name": "urgency",
"score": 1.62,
"confidence": 0.71,
"probabilities": [
{ "label": "Can wait", "value": 0, "probability": 0.02 },
{ "label": "Handle today", "value": 1, "probability": 0.34 },
{ "label": "Handle now", "value": 2, "probability": 0.64 }
]
}
],
"usage": {
"input_tokens": 312,
"input_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 0 },
"output_tokens": 30,
"output_tokens_details": { "reasoning_tokens": 0 },
"total_tokens": 342
}
}| Answer | Fields |
|---|---|
predicate | probability: probability the answer is yes, from 0 to 1 |
choice | choice: the most likely option, with the same type you sent (string or boolean) · confidence · probabilities: every option's probability |
score | score: probability-weighted level (can land between levels) · confidence · probabilities: every level's probability with its label and value |
refusal | The model returned no usable answer for that question. Other questions still answer |
confidence and probabilities are the model's own numbers. When a model does not report them, they are null; they are never estimated for you.
/v1/systemone
POST https://backend.sovereigneg.com/v1/systemone
This endpoint implements TypeSafe's System One contract, so a TypeSafe client's System One calls work once you point it at SovereignEG's base URL and API key. See Using the TypeSafe SDK.
Request
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Decision model ID (see Available models) |
state | string / object / array | Yes | The content to evaluate: plain text, structured data such as a chat log or a record, or an array mixing text with inline images |
questions | object | Yes | Named questions. You choose each key; the answer comes back under the same key |
Every question has a type and instructions, plus type-specific criteria:
type | criteria |
|---|---|
noul | Optional {"true": "...", "false": "..."} describing what yes and no mean |
choice | Required: a map of option → description (or null) |
score | Required: a list of level descriptions, lowest first |
instructions and every criteria description can be a string, an object, or an array. Put the question in one field and data it refers to in others, and point at them by name in backticks:
"instructions": {
"potential_duplicate": { "name": "John Smith", "location": "Oakland, California" },
"question": "Is the resume for the same person as `potential_duplicate`?"
}With an image, send state as an array: text items as plain strings, and each image as an object holding a base64 data URL:
"state": [
"Photo the courier sent on delivery.",
{ "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,..." } }
]Example
curl https://backend.sovereigneg.com/v1/systemone \
-H "Authorization: Bearer $SOVEREIGNEG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "jev-1.13",
"state": "I paid for my order twice and it still has not arrived after a week.",
"questions": {
"refund": {
"type": "noul",
"instructions": "Is the customer asking for money back?"
},
"team": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Charges, refunds, invoices",
"shipping": "Delivery and tracking",
"technical": "Bugs and outages"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this?",
"criteria": ["Can wait", "Handle today", "Handle now"]
}
}
}'import httpx
response = httpx.post(
"https://backend.sovereigneg.com/v1/systemone",
headers={"Authorization": "Bearer sk-..."},
json={
"model": "jev-1.13",
"state": "I paid for my order twice and it still has not arrived after a week.",
"questions": {
"refund": {"type": "noul", "instructions": "Is the customer asking for money back?"},
"team": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Charges, refunds, invoices",
"shipping": "Delivery and tracking",
"technical": "Bugs and outages",
},
},
},
},
timeout=30,
)
answers = response.json()["answers"]
if answers["refund"]["noul"] > 0.8:
route_to(answers["team"]["choice"])Response
One answer per question, under the keys you chose:
{
"model": "jev-1.13",
"answers": {
"refund": { "type": "noul", "noul": 0.96 },
"team": {
"type": "choice",
"choice": "billing",
"probabilities": { "billing": 0.84, "shipping": 0.14, "technical": 0.02 },
"confidence": 0.75
},
"urgency": {
"type": "score",
"score": 1.62,
"legend": { "0": "Can wait", "1": "Handle today", "2": "Handle now" },
"probabilities": { "0": 0.02, "1": 0.34, "2": 0.64 },
"confidence": 0.71
}
},
"usage": { "input_tokens": 312, "output_tokens": 30 }
}| Answer | Fields |
|---|---|
noul | noul: probability the answer is yes, from 0 to 1 |
choice | choice: the most likely option · probabilities: every option's probability · confidence |
score | score: probability-weighted level (can land between levels) · legend: level number → your description · probabilities · confidence |
Using the TypeSafe SDK
Point the official TypeSafe SDK at SovereignEG by changing its base URL and API key. The SDK adds /v1/systemone itself, so the base URL is the API origin without /v1:
from typesafe_sdk import TypeSafeClient
client = TypeSafeClient(
api_key="sk-...", # your SovereignEG API key
base_url="https://backend.sovereigneg.com",
)
result = client.system_one(
model="jev-1.13",
state="I paid for my order twice and it still has not arrived after a week.",
questions={
"refund": {"type": "noul", "instructions": "Is the customer asking for money back?"},
},
)
print(result.answers["refund"])import { TypeSafeClient } from '@typesafe-ai/sdk'
const client = new TypeSafeClient({
apiKey: process.env.SOVEREIGNEG_API_KEY,
baseURL: 'https://backend.sovereigneg.com',
})
const result = await client.systemOne({
model: 'jev-1.13',
state: 'I paid for my order twice and it still has not arrived after a week.',
questions: {
refund: { type: 'noul', instructions: 'Is the customer asking for money back?' },
},
})
console.log(result.answers.refund)Only systemOne / system_one is supported. The SDK's model listing calls GET /v1/models, which returns the SovereignEG catalog shape rather than TypeSafe's — browse the catalog instead.
Available models
Decision models are listed in the model catalog under Modality: Decision, or with GET https://backend.sovereigneg.com/v1/models where modality is "decision". The model page of each one shows ready-to-run code for that model, and input_modalities tells you whether it takes images.
Pricing
Decision models are billed per million input tokens — the content plus your questions — in Egyptian pounds, the same on both endpoints. The short typed answers carry no output charge on any decision model today. usage on every response reports the tokens billed.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | model_not_supported_on_endpoint | The model is not a decision model (or a decision model was sent to /v1/chat/completions). The message names the right endpoint |
| 400 | model_not_found | Unknown model ID |
| 400 | empty_input | input / state is empty |
| 400 | unsupported_input | The request carries images but the model's input_modalities lists only text. Pick a model that lists image |
| 400 | remote_media_not_supported / invalid_image_url | An image is a hosted URL, or its data URL is not a supported image type or is over the size limit. Inline it as a base64 data URL |
| 400 | too_many_image_parts | More than 20 images in one request |
| 400 | duplicate_choice | Two choices on one /v1/decisions question have the same value |
| 401 | missing_auth_header / invalid_api_key / key_revoked / key_expired / invalid_token | No Authorization: Bearer header; the sk- key is unknown, revoked or expired; or the token isn't an sk- key (invalid_token) |
| 402 | quota_exceeded | No spendable credit left. Top up in Dashboard → Billing |
| 402 | insufficient_balance | Your remaining credit can't cover this request. Top up, or send shorter content or fewer questions |
| 402 | spending_cap_reached / project_spend_cap_exceeded | The key's or the project's monthly spend cap is reached. Use a key with a higher cap (a key's cap can't be changed after creation), or raise the project cap under Dashboard → Projects → Limits |
| 422 | invalid_request_body | Malformed request: a missing field, an unknown question type, or choices / levels / criteria outside the limits above. param names the field |
| 429 | rate_limit_exceeded | Too many requests for your plan — back off and retry |
| 503 | provider_backings_unavailable | The model is temporarily unavailable — retry shortly |
Decision responses are never streamed: each request returns one JSON body.