Skip to main content

Decisions API Reference

RouteLLM exposes OpenAI's Decisions API at /v1/decisions. It accepts requests in the OpenAI Decisions format and returns responses in the same format.

Overview​

Decisions is not a chat endpoint. A single request evaluates an input (text, or user messages carrying text and inline images) against a list of typed questions, and returns a typed answer for each one. The model does not generate any text:

  • predicate: the probability, between 0 and 1, that a condition is true.
  • choice: one value from a fixed set, plus a probability for every option.
  • score: a probability-weighted position on a scale of ordered levels.

Because every possible answer is fixed before the request is sent, there is no generation step. That makes Decisions the fastest and cheapest way to get a bounded judgement from a frontier model. It suits classification, routing, moderation, triage and grading, anywhere you would otherwise prompt a chat model and parse a one-word reply.

The endpoint passes your request through to the provider. Your questions are forwarded unchanged, so any question field the Decisions API supports is accepted. Billing and credit tracking are handled on the Abacus.AI side.

Key Features​

  • Typed answers: Every answer is a probability, a value from your list, or a score. There is no free text to parse.
  • Several questions per request: Ask up to 10 questions about the same input in one call.
  • Image input: Questions can be evaluated against inline base64 images as well as text.
  • Low latency: Typical responses arrive in a few hundred milliseconds.
  • Input-only billing: You pay for input tokens only. Output tokens and cache reads are free.
note

The Decisions API serves gpt-6-luna only. It does not support streaming or tools. For open-ended generation, use /v1/responses or /v1/chat/completions.

Base URLs​

The Decisions endpoint lives at /v1/decisions under your RouteLLM base URL. The base URL depends on your organization type:

  • Self-Serve Organizations: https://routellm.abacus.ai/v1
  • Enterprise Platform: https://<workspace>.abacus.ai/v1

Replace <workspace> with your specific workspace identifier for enterprise deployments. To find your correct base URL, refer to the RouteLLM API page.

Authentication​

All requests require a RouteLLM API key in the Authorization header:

Authorization: Bearer <your_api_key>

You can obtain your API key from the Abacus.AI platform.

Supported Models​

ModelNotes
gpt-6-lunaThe only model the Decisions API serves

The thinking variants (gpt-6-luna-thinking, gpt-6-luna-high-thinking and so on) are not accepted, because there is no generation step to think in. Any other model returns a 400 error.

Request Parameters​

model (string, required)​

Must be gpt-6-luna.

input (string or array, required)​

The evidence that every question is evaluated against. Provide either:

  • a string of plain text, or
  • an array of user messages whose content mixes input_text and input_image parts.
"input": [
{
"role": "user",
"content": [
{ "type": "input_text", "text": "Customer photo of the returned item." },
{ "type": "input_image", "image_url": "data:image/png;base64,iVBORw0KGgo..." }
]
}
]

Images must be inline base64 data URLs. Hosted http(s):// image URLs and file_id references are not supported.

input is limited to 512,000 characters after serialization, and inline base64 images count toward that limit.

questions (array, required)​

Between 1 and 10 question objects. Every question needs:

  • name (string): unique within the request. The answer is returned under this name.
  • type (string): one of predicate, choice or score.
  • instructions (string): what to evaluate, written as a question or a condition.

choice and score questions take an extra field, described below. The whole questions array is limited to 512,000 characters after serialization.

Question Types​

Predicate​

Asks whether a condition is true. The answer is the probability that it is.

{
"name": "visible_damage",
"type": "predicate",
"instructions": "Does the description report a crack, tear or dent?"
}

Choice​

Picks one value from choices. Each choice has a value and an optional description that tells the model when that value applies.

{
"name": "department",
"type": "choice",
"instructions": "Which team should handle this ticket?",
"choices": [
{ "value": "billing", "description": "Charges, refunds, invoices, plan changes" },
{ "value": "technical", "description": "Bugs, errors, outages, integrations" },
{ "value": "account", "description": "Login, password, profile, permissions" }
]
}

Score​

Rates the input on ordered levels, from lowest to highest. Each level has a label and an optional description. The score is a probability-weighted level index, so it can fall between two levels. For example, 1.4 sits between the second and third level.

{
"name": "severity",
"type": "score",
"instructions": "How severe is the damage?",
"levels": [
{ "label": "minor", "description": "Cosmetic only; the device works normally" },
{ "label": "moderate", "description": "Partly usable or degraded" },
{ "label": "total", "description": "Unusable or will not power on" }
]
}

Response Format​

The response contains one answer per question in answers, in the order the questions were asked, along with the model and token usage:

{
"answers": [
{
"type": "predicate",
"name": "visible_damage",
"probability": 0.97
},
{
"type": "choice",
"name": "department",
"choice": "technical",
"probabilities": [
{ "value": "billing", "probability": 0.02 },
{ "value": "technical", "probability": 0.95 },
{ "value": "account", "probability": 0.03 }
],
"confidence": 0.93
},
{
"type": "score",
"name": "severity",
"score": 1.86,
"probabilities": [
{ "value": 0, "label": "minor", "probability": 0.01 },
{ "value": 1, "label": "moderate", "probability": 0.12 },
{ "value": 2, "label": "total", "probability": 0.87 }
],
"confidence": 0.78
}
],
"model": "gpt-6-luna",
"usage": {
"input_tokens": 284
}
}
Answer typeFields
predicateprobability: probability that the condition is true, 0 to 1
choicechoice: the most likely value. probabilities: one entry per option. confidence: how concentrated the distribution is, 0 to 1
scorescore: probability-weighted level index, starting at 0. probabilities: one entry per level. confidence: 0 to 1
tip

Use the probabilities as well as the top answer. You can set your own thresholds, for example acting automatically on a predicate above 0.9 and sending anything between 0.4 and 0.9 to a person for review.

Pricing​

Decisions is billed on input tokens only, at the provider's price of $0.10 per 1M input tokens. Output tokens and cache reads are not charged. If the provider does not return a usage block for a request, the input tokens are estimated from the size of the request.

Errors​

Errors use the OpenAI error envelope, so OpenAI-compatible clients can read them:

{
"error": {
"message": "Too many questions (12); the limit is 10.",
"type": "invalid_request_error",
"param": null,
"code": null
}
}
StatustypeCause
400invalid_request_errorMissing or unsupported model; missing, empty or oversized input; empty, oversized or more than 10 questions; a question without a name, with a duplicate name, or with an unknown type; or the provider rejected a question's fields
403permission_deniedThe model is not available to your organization or plan
429rate_limit_exceededYour organization is out of credits, or the Decisions API is temporarily at capacity. Retry with backoff
503server_errorThe Decisions API is temporarily unavailable

Code Examples​

The Decisions API has no dedicated method in the OpenAI SDKs this example targets, so the Python and TypeScript examples send the request with the SDK's generic post method. That still uses the SDK's authentication, base URL and retry handling.

from openai import OpenAI

client = OpenAI(
base_url="<your base url>",
api_key="<your_api_key>",
)

decision = client.post(
"/decisions",
body={
"model": "gpt-6-luna",
"input": "The screen is cracked right across the middle and the device will not boot.",
"questions": [
{
"name": "visible_damage",
"type": "predicate",
"instructions": "Does the description report a crack, tear or dent?",
},
{
"name": "severity",
"type": "score",
"instructions": "How severe is the damage?",
"levels": [
{"label": "minor"},
{"label": "moderate"},
{"label": "total"},
],
},
],
},
cast_to=object,
)

for answer in decision["answers"]:
print(answer)

Best Practices​

  1. Ask every question about the same input in one request, rather than making one call per question. All the questions share the same input tokens.
  2. Write each instructions string as a single, specific condition or question. Use description on choices and levels to settle the cases where the boundary is unclear.
  3. Use choice when the options have no order and score when they do. A score tells you how far along the scale an input sits, not just which level is most likely.
  4. Act on the probabilities with your own thresholds, rather than trusting the top answer every time.
  5. Use /v1/responses or /v1/chat/completions when you need an explanation or other generated text.