A billing label should move a ticket to the right queue, not move money. That is the boundary I would preserve when adopting OpenAI’s Decisions API: let the model interpret a messy message, then let application rules decide what may happen next. A well-formed answer can still be wrong or insufficient to authorize an action.
Decisions returns a probability, a supplied category or a rubric score instead of a free-form explanation. This guide explains those answer shapes, shows a corrected JSON example, and works through threshold and caching choices. The aim is to make a small judgment useful to software while keeping evidence checks, human review and consequential actions under separate control.

- A typed result makes parsing simpler; it does not prove correctness.
- A score’s average can hide a very different distribution of possible outcomes.
- A routing threshold needs local labeled examples and a defined cost of mistakes.
- Cached input, new input and cache writes are separate billing categories—not extra tokens to add to usage twice.
First, understand what the endpoint decides
An API is the interface software calls to request work. A typed answer has an expected shape, such as a category from a fixed list, rather than arbitrary prose. OpenAI’s October 22 changelog marks Decisions as generally available. The endpoint is POST /v1/decisions, currently using gpt-6-luna.
Think of a support desk receiving an unclear complaint. The model can interpret what the person seems to mean; code can check the account, required permissions and allowed workflow. Neither the word “billing” nor a high probability proves that an order has been charged twice.
Read Figure 1: Follow the result through the routing gate. The lower layer requires separate evidence and authority before a billing change can occur.
Use ordinary code when a reliable structured rule already answers the question. Use Decisions when the judgment needs interpretation and a bounded answer is enough. For custom extracted fields or a generated explanation, OpenAI points to Responses with Structured Outputs; for requesting a tool with arguments, it points to function calling. Those tools also need application-side authorization.
OpenAI describes Decisions as about ten times faster than Responses. Treat that as a vendor comparison, not a latency promise for your workflow. Measure the same inputs and question definitions, include routing and fallback time, and check that the faster path still meets your quality bar.
Choose a condition, a category or an ordered rubric
The API reference defines three question types. A predicate estimates whether one condition is true. A choice selects from supplied values. A score uses ordered levels and returns their probability-weighted average index. A question can also return refusal; other questions in that request can still have answers.
Read Figure 2: Begin with what your code needs to receive. Departments have no natural order, so routing is a choice rather than a severity score.
Write one observable criterion at a time. “Is there visible damage?” differs from “Should we refund the customer?” The second mixes visual evidence with purchase history and policy. Distinct category descriptions reduce overlap; an other option helps when the list does not cover the request, but it is not a formal API requirement for every choice list.
For severity, define what each level means before looking at results. “Cosmetic,” “workaround available” and “fully blocked” are ordered conditions. Their numeric positions start at zero; the distance between positions is a scoring convention, not a measurement of dollars lost.
Do not throw away the distribution behind a score
For levels 0, 1 and 2, a score is 0×p0 + 1×p1 + 2×p2. Consider two worked distributions. A assigns all probability to level 1: [0, 1, 0]. B assigns half to each extreme: [0.5, 0, 0.5]. Both return an average of 1.0.
Read Figure 3: Compare the probability of level 2, not just the average. The same score can represent certainty about the middle or a split between opposite outcomes.
If a fully blocked issue needs urgent review, B may deserve different handling from A even though their scores match. A rule using only score >= 1 loses that distinction. Preserve the per-level probabilities when the application cares about a particular severe outcome.
Choice and score answers also have a separate confidence field. Do not silently replace it with the largest option probability or interpret it as a guaranteed accuracy percentage. Keep the fields distinct and test how each relates to labeled outcomes in your own data. Predicates expose the condition probability rather than that same choice/score confidence shape.
A corrected support-routing JSON example
Here is a proposed request body for POST /v1/decisions using fictional evidence. The input_json part contains data, inside a user message’s content array. One posted charge plus one pending charge is deliberately inconclusive evidence for a duplicate completed payment.
{
"model": "gpt-6-luna",
"input": [
{
"role": "user",
"content": [
{
"type": "input_text",
"text": "Route this fictional support ticket. Routing does not authorize a refund."
},
{
"type": "input_json",
"data": {
"ticket": {
"body": "I see two charges for this order."
},
"order": {
"charges": [
{
"id": "a",
"amount": 49,
"status": "posted"
},
{
"id": "b",
"amount": 49,
"status": "pending"
}
]
}
}
}
]
}
],
"questions": [
{
"type": "choice",
"name": "department_route",
"instructions": "Which team should review the complaint? Do not decide refund eligibility.",
"choices": [
{
"value": "billing",
"description": "Charges, invoices and payment questions."
},
{
"value": "technical",
"description": "Product malfunction or integration problems."
},
{
"value": "shipping",
"description": "Delivery or tracking problems."
},
{
"value": "other",
"description": "No suitable category or unclear request."
}
]
}
]
}
A hypothetical response excerpt with the documented field shapes:
{
"answers": [
{
"type": "choice",
"name": "department_route",
"choice": "billing",
"probabilities": [
{
"value": "billing",
"probability": 0.9
},
{
"value": "technical",
"probability": 0.03
},
{
"value": "shipping",
"probability": 0.02
},
{
"value": "other",
"probability": 0.05
}
],
"confidence": 0.82
}
]
}
Read choice, not a top-level value, to get the selected category. The probabilities field is an array of value/probability objects, not a dictionary keyed by department. Match the answer’s name and type before using it. Handle refusals, unknown types and transport errors explicitly rather than treating them as a negative condition.
In this example, routing to billing is reasonable; refund eligibility remains unresolved. Verify settled payment records, order relationships and the organization’s authorization policy in a separate billing workflow. Equal amounts alone do not establish a duplicate charge. Validate what the actual API returns before connecting the router to consequential actions.
Shared evidence does not create a chain of questions
The GA update raises the request limit from 200 to 400 questions and adds JSON input and question-specific images. Independent questions can share evidence. When question B depends on A’s answer, construct B in a later request rather than expecting it to read A inside the same array.
Read Figure 4: The upper branch asks two independent questions about the same product. The lower branch waits for an answer before the application chooses its follow-up.
Keep shared reference material in input and candidate-specific material in the relevant question instructions. Files, raw audio and item references are not interchangeable with accepted text/image/JSON parts. Conversation tool-call history is evidence for evaluation; it does not turn this endpoint into a tool-execution service.
When processing several questions, record each named outcome. A refusal on one question should not erase unrelated successful answers, nor should a successful answer hide a failed one. If your policy needs all required checks to pass, enforce that requirement in code.
Tune thresholds around mistakes, not a universal cutoff
A false positive is a condition flagged as present when it is absent. A false negative is a real condition the screen misses. For a predicate that screens reports for review, raising the cutoff may reduce false alarms while missing more reports. The right balance depends on the consequence of each error.
The following constructed set contains 100 positive and 900 negative cases. At a cutoff of 0.70, assume 90 true positives and 45 false positives. At 0.90, assume 70 true positives and 9 false positives. These are invented counts for explaining the tradeoff, not test results or recommended thresholds.
Read Figure 5: Precision asks how many positive predictions were correct; recall asks how many actual positives were found. The stricter rule improves one here while reducing the other.
The first rule has precision 90/(90+45) = 66.7% and recall 90/100 = 90%. The stricter rule has precision 70/79 ≈ 88.6% and recall 70%. If missing a case is expensive, the second rule may be worse despite fewer false alarms.
Calibration is a different question: among labeled cases assigned probabilities near 0.8, does the condition occur roughly that often? Check that relationship separately from precision at one cutoff. Keep tuning and final evaluation samples separate, include ambiguous and out-of-scope cases, and reassess after changing questions or input populations.
Start in shadow mode: record what the proposed router would do while the existing process remains authoritative. Minimize sensitive data sent or logged, route uncertainty to review, and monitor refusal, fallback, error and routing outcomes separately. Do not choose an arbitrary fixed sample size and call the system validated.
Put the cache boundary and token charges in the same worksheet
Decisions caches an eligible matching prefix of shared input; question content lies outside that reusable prefix. A repeated long rubric inside questions therefore does not automatically receive the shared-input cache discount. The documented minimum reusable prefix is 1,024 tokens.
Read Figure 6: The dotted line is an accounting boundary, not a trust boundary. Changed question material still counts toward input even when shared reference material is reused.
The Standard Luna rates and Decisions pricing section list $0.10 per million uncached input tokens, $0.01 cached input, and $0.125 for default cache writes. Decisions output tokens are not charged; do not substitute Luna’s Responses output rate. Regional and long-context multipliers may apply.
Worked cost example. Assume one request reports 10,000 total input tokens, including 6,000 cache-read tokens and 2,000 cache-write tokens, with the remaining 2,000 ordinary uncached tokens. Assume Standard base rates, no regional premium and no long-context multiplier:
Read: 6,000 × $0.01 / 1,000,000 = $0.00006
Write: 2,000 × $0.125 / 1,000,000 = $0.00025
Uncached: 2,000 × $0.10 / 1,000,000 = $0.00020
Estimated token charge $0.00051
The read and write counts are subsets of usage.input_tokens; adding them to the total again double-counts usage. Cache-write rates are total write rates, not a surcharge added to ordinary input for the same token. Confirm the categories in actual usage, and count retries and review costs when evaluating the whole workflow.
The current Decisions reference lists only ttl: "30m". The general prompt-caching guide documents a 12-hour option specifically for Responses; do not copy it into Decisions. A minimum cache lifetime is also not a deletion deadline or a latency guarantee.
Keep retention and regional processing separate from routing
OpenAI’s data controls describe default abuse-monitoring logs of up to 30 days and ZDR eligibility with limitations. They also describe encrypted GPU-local cache state with a 24-hour expiration. Those are separate concepts from the request’s minimum cache lifetime.
The documented image exception is specific: potential child sexual abuse material (CSAM) detected by the submission classifier can be retained for manual review even under ZDR. Do not broaden that into “all safety flags” or promise that enabling ZDR removes every retention path.
Regional availability and data residency do not prove inference runs in that same region. Decisions regional processing is currently documented for the US and Europe (EEA plus Switzerland). Check the endpoint, organization eligibility and current terms before sending regulated or confidential data. This article does not determine compliance for your application.
My release rule is simple: verify the request shape, evaluate the judgment on local labeled cases, enforce permissions outside the model, and keep a reversible fallback. Typed answers make software integration more direct. They do not remove the work of deciding what evidence is sufficient and who may act on it.
Sources and scope — checked October 24, 2026. Product behavior comes from the official OpenAI documentation below. Routing gates, response numbers, score distributions, threshold counts and costs are proposed or worked examples with stated assumptions.