Decisions API is in public beta
Mirrored from Hacker News — AI on Front Page for archival readability. Support the source by reading on the original site.
The Decisions API evaluates text, images, or both and returns typed answers about 10x faster than the Responses API. Get the probability that a condition is true, a choice from a fixed set, or a score against a rubric. Use those answers to classify content, route requests, and prioritize work in your application.
Try the Decisions API in the Playground to experiment with questions and inputs before writing code.
The Decisions API is in public beta, and we expect to GA in the coming weeks.
gpt-6-luna is the only model currently available. Use the dedicated POST /v1/decisions endpoint.
To run the SDK examples below, use these OpenAI SDK versions or later: Python 3.26.0, JavaScript 7.30.0, Go 3.73.0, Ruby 0.101.0, and Java 4.78.0. See OpenAI SDK for installation instructions.
How decisions work
A request has three parts:
| Field | Purpose |
|---|---|
model |
The model that evaluates the request. Currently, only gpt-6-luna is supported. |
input |
Shared evidence for the questions: a text string or user messages containing text and images. |
questions |
What to evaluate, including each question’s type, instructions, and any allowed choices or score levels. |
The response contains an answers array. Give each question a unique name to identify its answer; the API echoes that name in the response.
Choose a question type
| Type | Use it to | Main result |
|---|---|---|
predicate |
Check a condition, such as visible damage or passage relevance. | probability: an estimate from 0 to 1 that the condition is true. |
choice |
Select one option, such as a department or content category. | choice: one of your supplied values. |
score |
Rate an input against ordered levels, such as issue severity. | score: the probability-weighted average of the level indices. |
Both choice and score return probabilities over discrete options. Use choice for categories without an order, such as departments. Use score for ordered levels, such as severity; it takes the probability-weighted average of their numeric indices to produce a score that can fall between levels.
Use Decisions when your application needs one of these answer types. Use Structured Outputs with the Responses API when you need to generate an object that follows your own JSON schema, such as extracted fields or a written explanation, or function calling when you need a model to request a tool call with arguments.
Check an image for visible damage
Use a predicate question to check a product photo for visible damage. This request combines the image with instructions to look for a crack, tear, or dent.
Does this item have a dent?


Please cancel my subscription before the next renewal.
Can I switch to annual billing and keep my current plan?
I don’t need this anymore. How do I stop future charges?
Can I return an item after 30 days?
Returns are accepted within 30 days of delivery. After that, items aren’t eligible for a refund.
Start a return from the Orders page in your account.
Standard shipping takes three to five business days.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22IMAGE_BASE64="$(base64 < product.png | tr -d '\r\n')"
curl https://api.openai.com/v1/decisions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
"model": "gpt-6-luna",
"input": [{
"role": "user",
"content": [
{"type": "input_text", "text": "Inspect the product in this photo."},
{"type": "input_image", "image_url": "data:image/png;base64,$IMAGE_BASE64"}
]
}],
"questions": [{
"type": "predicate",
"name": "visible_damage",
"instructions": "Does the product have visible damage, such as a crack, tear, or dent? Ignore shadows and damage to the packaging."
}]
}
JSON1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35import { readFile } from "node:fs/promises";
import OpenAI from "openai";
const client = new OpenAI();
const imageBase64 = (await readFile("product.png")).toString("base64");
const decision = await client.decisions.create({
model: "gpt-6-luna",
input: [
{
role: "user",
content: [
{ type: "input_text", text: "Inspect the product in this photo." },
{
type: "input_image",
image_url: `data:image/png;base64,${imageBase64}`,
},
],
},
],
questions: [
{
type: "predicate",
name: "visible_damage",
instructions:
"Does the product have visible damage, such as a crack, tear, or dent? Ignore shadows and damage to the packaging.",
},
],
});
const answer = decision.answers[0];
if (answer.type === "refusal") {
console.log(`Refused: ${answer.name}`);
} else if (answer.type === "predicate") {
console.log(`Visible damage probability: ${answer.probability}`);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39import base64
from pathlib import Path
from openai import OpenAI
client = OpenAI()
image_base64 = base64.b64encode(Path("product.png").read_bytes()).decode("ascii")
decision = client.decisions.create(
model="gpt-6-luna",
input=[
{
"role": "user",
"content": [
{"type": "input_text", "text": "Inspect the product in this photo."},
{
"type": "input_image",
"image_url": f"data:image/png;base64,{image_base64}",
},
],
}
],
questions=[
{
"type": "predicate",
"name": "visible_damage",
"instructions": (
"Does the product have visible damage, such as a crack, tear, or dent? "
"Ignore shadows and damage to the packaging."
),
}
],
)
answer = decision.answers[0]
if answer.type == "refusal":
print(f"Refused: {answer.name}")
elif answer.type == "predicate":
print(f"Visible damage probability: {answer.probability}")1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50package main
import (
"context"
"encoding/base64"
"fmt"
"os"
"github.com/openai/openai-go/v3"
)
func main() {
image, err := os.ReadFile("product.png")
if err != nil {
panic(err)
}
client := openai.NewClient()
decision, err := client.Decisions.New(context.Background(), openai.DecisionNewParams{
Model: "gpt-6-luna",
Input: openai.DecisionNewParamsInputUnion{
OfDecisionInputMessageArray: []openai.DecisionInputMessageParam{{
Content: openai.DecisionInputMessageContentUnionParam{
OfParts: []openai.DecisionInputPartUnionParam{
{OfInputText: &openai.DecisionInputTextParam{Text: "Inspect the product in this photo."}},
{OfInputImage: &openai.DecisionInputImageParam{
ImageURL: "data:image/png;base64," + base64.StdEncoding.EncodeToString(image),
}},
},
},
}},
},
Questions: []openai.DecisionNewParamsQuestionUnion{{
OfPredicate: &openai.DecisionNewParamsQuestionPredicate{
Name: openai.String("visible_damage"),
Instructions: "Does the product have visible damage, such as a crack, tear, or dent? Ignore shadows and damage to the packaging.",
},
}},
})
if err != nil {
panic(err)
}
switch answer := decision.Answers[0].AsAny().(type) {
case openai.DecisionAnswerPredicate:
fmt.Println(answer.Probability)
case openai.DecisionAnswerRefusal:
fmt.Printf("Decision refused for %s\n", answer.Name)
default:
panic("unexpected answer type")
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47import com.openai.models.decisions.DecisionCreateParams;
import com.openai.models.decisions.DecisionInputImage;
import com.openai.models.decisions.DecisionInputMessage;
import com.openai.models.decisions.DecisionInputPart;
import com.openai.models.decisions.DecisionInputText;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.List;
String imageBase64 =
Base64.getEncoder().encodeToString(Files.readAllBytes(Path.of("product.png")));
var message =
DecisionInputMessage.builder()
.contentOfParts(
List.of(
DecisionInputPart.ofInputText(
DecisionInputText.builder()
.text("Inspect the product in this photo.")
.build()),
DecisionInputPart.ofInputImage(
DecisionInputImage.builder()
.imageUrl("data:image/png;base64," + imageBase64)
.build())))
.build();
var decision =
client
.decisions()
.create(
DecisionCreateParams.builder()
.model("gpt-6-luna")
.inputOfDecisionInputMessages(List.of(message))
.addQuestion(
DecisionCreateParams.Question.Predicate.builder()
.name("visible_damage")
.instructions(
"Does the product have visible damage, such as a crack, tear, or"
+ " dent? Ignore shadows and damage to the packaging.")
.build())
.build());
var answer = decision.answers().get(0);
if (answer.isRefusal()) {
System.out.println("Refused: " + answer.asRefusal().name().orElse("visible_damage"));
} else {
System.out.println(answer.asPredicate().probability());
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41require "base64"
require "openai"
image_base64 = Base64.strict_encode64(File.binread("product.png"))
client = OpenAI::Client.new
decision = client.decisions.create(
model: "gpt-6-luna",
input: [
{
role: :user,
content: [
{
type: :input_text,
text: "Inspect the product in this photo."
},
{
type: :input_image,
image_url: "data:image/png;base64,#{image_base64}"
}
]
}
],
questions: [
{
type: :predicate,
name: "visible_damage",
instructions: "Does the product have visible damage, such as a crack, tear, or dent? Ignore shadows and damage to the packaging."
}
]
)
answer = decision.answers.fetch(0)
case answer
when OpenAI::Models::Decision::Answer::Predicate
puts(answer.probability)
when OpenAI::Models::Decision::Answer::Refusal
warn("Decision refused for #{answer.name}")
else
raise("Unexpected answer type: #{answer.type}")
endAn illustrative response excerpt:
123456789{
"answers": [
{
"type": "predicate",
"name": "visible_damage",
"probability": 0.92
}
]
}
The probability is the model’s estimate that the condition is true. Use it to flag photos for review based on a threshold you choose.
Images must be inline base64 data URLs. Hosted HTTP or HTTPS image URLs and file_id inputs aren’t supported by this endpoint. Combine input_text and input_image parts in a user message to evaluate images together with instructions or other context.
Select from fixed options
A choice question selects one value from the options you provide. Use distinct values and descriptions that explain when each option applies.
Which lane should the car choose?
I was charged twice for this month. Can you refund the extra payment?
Every CSV export fails with an error, even after I refresh the page.
I lost my phone and can’t get past two-step verification.
Invoice
Billed to Cedar & Co.
Payment due October 21
Discussion (0)
Sign in to join the discussion. Free account, 30 seconds — email code or GitHub.
Sign in →No comments yet. Sign in and be the first to say something.