Skip to main content

Decisions

celeris-1-decision answers questions about text or images with probabilities. Each answer comes back as a number or a choice you can threshold, rank, or route on. Choose the API format that matches your integration:

SDKEndpoint
Jev SDKPOST /v1/systemone
OpenAI SDKPOST /v1/decisions

Both endpoints serve the same model and share its price and rate limits. Each response is one JSON body. There is no streaming.

System One API​

Send model: "celeris-1-decision", a state containing your data, and named questions to POST /v1/systemone. It implements TypeSafe's System One API, so code written for Jev with the Jev SDK runs against it once you change the base URL, key, and model name.

A yes/no question​

curl https://inference.celeris.ai/celeris-1-decision/v1/systemone \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"state": "I was charged twice this month. Please refund one of the payments.",
"questions": {
"refund": {"type": "noul", "instructions": "The customer is asking for a refund."}
}
}'
{
"model": "celeris-1-decision",
"answers": {
"refund": {"type": "noul", "noul": 0.95}
},
"usage": {"input_tokens": 122, "output_tokens": 0}
}

noul is the probability that the answer is yes, from 0 to 1. The responses shown on this page are examples; values can vary.

To switch existing code without editing it, set the SDK's environment variables:

export TYPESAFE_BASE_URL=https://inference.celeris.ai/celeris-1-decision
export TYPESAFE_API_KEY=$CELERIS_API_KEY
export TYPESAFE_DEFAULT_MODEL=celeris-1-decision

Question types​

Each question needs a type and usually carries instructions. One request can hold several questions of any mix of types, and state can be a string or any other JSON value.

typeAnswer
noulnoul: the probability of yes.
choicechoice: the most likely option. probabilities: one per option.
scorescore: the average level, weighted by probability. probabilities: one per level. legend: each level's description.

For noul, criteria is optional. Use {"true": ..., "false": ...} to describe each outcome. For choice, criteria is an object of at least two options. Each key is an option name and each value describes it, or is null. For score, criteria is an array of at least two levels, lowest first. Levels are numbered from 0.

choice and score answers also carry confidence, the top probability rescaled so that 0 is an even split across the options and 1 is certainty. Probabilities are rounded to two decimal places and sum to 1.

curl https://inference.celeris.ai/celeris-1-decision/v1/systemone \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"state": {
"subject": "Charged twice",
"body": "I was charged twice this month and nobody has answered my emails for a week. Please refund one of the payments."
},
"questions": {
"refund": {"type": "noul", "instructions": "The customer is asking for a refund."},
"team": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": {
"billing": "Payments, invoices and refunds.",
"technical": "Bugs and outages.",
"sales": "Upgrades and quotes."
}
},
"frustration": {
"type": "score",
"instructions": "How frustrated is the customer?",
"criteria": ["Calm.", "Annoyed.", "Angry."]
}
}
}'
{
"model": "celeris-1-decision",
"answers": {
"refund": {"type": "noul", "noul": 0.98},
"team": {
"type": "choice",
"choice": "billing",
"probabilities": {"billing": 0.97, "technical": 0.02, "sales": 0.01},
"confidence": 0.96
},
"frustration": {
"type": "score",
"score": 1.37,
"probabilities": {"0": 0.03, "1": 0.57, "2": 0.40},
"confidence": 0.36,
"legend": {"0": "Calm.", "1": "Annoyed.", "2": "Angry."}
}
},
"usage": {"input_tokens": 231, "output_tokens": 0}
}

Celeris extensions​

Celeris adds options that System One does not have. They go in one optional top-level object, x_celeris. The Jev SDK sends it through extra_body.

Explanations​

Set explain to true to get one sentence per question on why the model picked its answer. The sentences come back in x_celeris.explanations, keyed by question name. Explanations make the request slower.

curl https://inference.celeris.ai/celeris-1-decision/v1/systemone \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"state": "I was charged twice this month and nobody has answered my emails for a week.",
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": {
"billing": "Payments, invoices and refunds.",
"technical": "Bugs and outages.",
"sales": "Upgrades and quotes."
}
}
},
"x_celeris": {"explain": true}
}'
{
"model": "celeris-1-decision",
"answers": {
"team": {
"type": "choice",
"choice": "billing",
"probabilities": {"billing": 0.97, "technical": 0.02, "sales": 0.01},
"confidence": 0.96
}
},
"usage": {"input_tokens": 128, "output_tokens": 15},
"x_celeris": {
"explanations": {
"team": "The customer reports being charged twice, which is a payments and billing issue."
}
}
}

Images​

Attach images in images, an object that maps a name to a base64 data URL. Images are part of the state, and your state and questions can refer to one by its name.

max_soft_tokens sets the resolution the model reads every image in the request at. It takes the values listed there.

IMAGE_B64=$(base64 < receipt.png | tr -d '\n')

curl https://inference.celeris.ai/celeris-1-decision/v1/systemone \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"state": {"claim": {"amount": 13.50, "category": "meals"}},
"questions": {
"matches": {"type": "noul", "instructions": "The receipt total matches the claimed amount."}
},
"x_celeris": {
"images": {"receipt": "data:image/png;base64,'"$IMAGE_B64"'"},
"max_soft_tokens": 560
}
}'

OpenAI Decisions API​

Send your data as input and a list of questions to POST /v1/decisions. The endpoint uses the OpenAI Decisions API format. Point the OpenAI SDK at the Celeris base URL, supply your Celeris API key, and set model to celeris-1-decision.

A yes/no question​

curl https://inference.celeris.ai/celeris-1-decision/v1/decisions \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"input": "I was charged twice this month. Please refund one of the payments.",
"questions": [
{
"type": "predicate",
"name": "refund",
"instructions": "The customer is asking for a refund."
}
]
}'
{
"model": "celeris-1-decision",
"answers": [
{"type": "predicate", "name": "refund", "probability": 0.95}
],
"usage": {
"input_tokens": 122,
"input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0},
"output_tokens": 0,
"output_tokens_details": {"reasoning_tokens": 0},
"total_tokens": 122
}
}

probability is the chance that the statement is true, from 0 to 1. The responses shown on this page are examples; values can vary.

The OpenAI Python SDK needs version 3.26.0 or later for client.decisions. Include /v1 in its base_url.

Question types​

One request can mix question types. Give each question instructions that describe what to evaluate. A name is optional; when supplied, it must be nonempty and unique within the request. Answers follow the order of your questions and echo any names you supplied.

typeAnswer
predicateprobability: the probability that the statement is true.
choicechoice: the most likely value. probabilities: a list of values and their probabilities.
scorescore: the average level index, weighted by probability. probabilities: a list with each level's numeric value, label, and probability.

A choice question needs choices, at least two objects with a value and optional description. A score question needs levels, at least two objects with a label and optional description, lowest first.

Score levels are numbered from 0. choice and score answers also carry confidence, the top probability rescaled so that 0 is an even split across the options and 1 is certainty.

Choice values can be strings or booleans, and the response preserves their types. Values must be unique. A single question cannot include both true and "true", or both false and "false".

curl https://inference.celeris.ai/celeris-1-decision/v1/decisions \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"input": "I was charged twice this month and nobody has answered my emails for a week. Please refund one of the payments.",
"questions": [
{"type": "predicate", "name": "refund", "instructions": "The customer is asking for a refund."},
{
"type": "choice",
"name": "team",
"instructions": "Which team should handle this ticket?",
"choices": [
{"value": "billing", "description": "Payments, invoices and refunds."},
{"value": "technical", "description": "Bugs and outages."},
{"value": "sales", "description": "Upgrades and quotes."}
]
},
{
"type": "score",
"name": "frustration",
"instructions": "How frustrated is the customer?",
"levels": [{"label": "Calm"}, {"label": "Annoyed"}, {"label": "Angry"}]
}
]
}'

The answers list for this request looks like this:

[
{"type": "predicate", "name": "refund", "probability": 0.98},
{
"type": "choice",
"name": "team",
"choice": "billing",
"probabilities": [
{"value": "billing", "probability": 0.97},
{"value": "technical", "probability": 0.02},
{"value": "sales", "probability": 0.01}
],
"confidence": 0.96
},
{
"type": "score",
"name": "frustration",
"score": 1.37,
"probabilities": [
{"value": 0, "label": "Calm", "probability": 0.03},
{"value": 1, "label": "Annoyed", "probability": 0.57},
{"value": 2, "label": "Angry", "probability": 0.40}
],
"confidence": 0.36
}
]

Celeris extensions​

Celeris options go in the optional top-level x_celeris object. The OpenAI SDK sends it through extra_body.

Explanations​

Set x_celeris.explain to true to get one sentence per question explaining the answer. The response adds x_celeris.explanations, a list in the same order as answers. Explanations make the request slower.

curl https://inference.celeris.ai/celeris-1-decision/v1/decisions \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"input": "I was charged twice this month. Please refund one of the payments.",
"questions": [
{"type": "predicate", "name": "refund", "instructions": "The customer is asking for a refund."}
],
"x_celeris": {"explain": true}
}'

The added response field looks like this:

{
"x_celeris": {
"explanations": ["The customer explicitly asks for one of the payments to be refunded."]
}
}

Images​

For images, send input as a list of user messages with input_text and input_image content parts. An image's image_url must be a base64 data URL. External URLs and file IDs are not supported.

IMAGE_B64=$(base64 < receipt.png | tr -d '\n')

curl https://inference.celeris.ai/celeris-1-decision/v1/decisions \
-H "Authorization: Bearer $CELERIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "celeris-1-decision",
"input": [{
"role": "user",
"content": [
{"type": "input_text", "text": "The expense claim is for $13.50 in meals."},
{"type": "input_image", "image_url": "data:image/png;base64,'"$IMAGE_B64"'"}
]
}],
"questions": [
{"type": "predicate", "name": "matches", "instructions": "The receipt total matches the claimed amount."}
],
"x_celeris": {"max_soft_tokens": 560}
}'

x_celeris.max_soft_tokens sets the resolution for every image in the request. The image detail field accepts low, high, auto, or original, but does not change the resolution.

Input and compatibility​

input accepts a string or a list of user messages. A message's content can be a string or a list of text and image parts. For structured data, serialize it to a string, such as input=json.dumps(ticket) in Python. Other message roles, tools, audio, and files are not supported.

The model reads all text parts in order, joined with blank lines. It reads images separately in the order you sent them, named image_1, image_2, and so on. With several images, refer to those names in your questions. Text next to an image is not kept attached to it.

safety_identifier accepts a string or null and has no effect on the request. Unknown fields, including stream, return a validation error.

Request limits​

  • Up to 512 questions per request, or 64 with x_celeris.explain: true.
  • Up to 512 options per choice question.
  • Up to 64 levels per score question.
  • Up to 8 images per request, each at most 25 megapixels, or 25,000,000 pixels.
  • Up to 100,000 JSON values per request body.

Long question names can require smaller batches, even within these counts. These limits apply to both endpoints. On /v1/decisions, the option limit applies to choices and the score level limit applies to levels. Exceeding a limit returns 400 invalid_request on /v1/decisions, or a 422 with details in msg on /v1/systemone. The maximum request body size is 8 MiB; larger bodies return a 413.

Usage and cost​

The usage block reports input_tokens and output_tokens. Input tokens are billed at the celeris-1-decision rate, and output tokens are free. Images count as input tokens.

On /v1/decisions, usage also includes total_tokens, the sum of input and output tokens. Its cache and reasoning token detail fields are present and set to zero.

input_tokens covers everything the model reads for the request, which is more than your state and questions alone. Read it from the response instead of estimating it from your payload. The yes/no request above reported 122 input tokens, costing US$0.00000488.

Use the Server-Timing header to measure server processing time.

Errors​

On /v1/decisions, an invalid request returns 400 invalid_request in the OpenAI error envelope. The message identifies the problem and error.param names the top-level field, or is null for a problem with the whole body. The OpenAI Python SDK raises BadRequestError for this status.

On /v1/systemone, an invalid request returns a 422 with a detail array. This includes malformed JSON, an unrecognised field such as stream, or a model other than celeris-1-decision.

See Errors for 400 request_rejected and how to correct the request. Statuses such as 401, 402, 413, 429, and 502 behave as described in Errors, and rate limits apply to both endpoints as for any other model.