# OpenAI Decisions API: Can You Use It Yet, and What to Ship Now

> As of October 6, 2026, OpenAI's Decisions API is a limited preview with no public docs or price. Ship the same decision on GPT-6 Luna with a strict enum schema.

- Source: https://www.aifreeapi.com/en/posts/openai-decisions-api
- Language: en
- Published: 2026-10-06
- Updated: 2026-10-06
- Publisher: AI Free API (https://www.aifreeapi.com)

OpenAI's Decisions API exists, but most developers can't call it yet. As of October 6, 2026, it is a limited preview for selected API customers, and OpenAI's developer docs have no reference page, request schema, price, or rate limits for it. In a [test published by eesel AI](https://www.eesel.ai/blog/openai-decisions-api), a standard API key calling `POST /v1/decisions` got HTTP 403 with the message "Decision API is not enabled for this user."

You don't have to wait to ship the feature. GPT-6 Luna, the model OpenAI says powers the endpoint, already accepts text and images, and Structured Outputs can force it to answer only from your own list. At an assumed 400 input and 15 output tokens per decision, that costs $47.50 per million decisions at Luna's Standard rates. Put the call behind a small interface, give the model a "needs review" answer, and switch once OpenAI publishes docs and a price.

## What the Decisions API does: bounded questions with predefined answers

OpenAI announced the Decisions API at DevDay on September 29, 2026. The [DevDay announcement thread](https://community.openai.com/t/devday-2026-announcements-and-developer-resources/1402006) on the OpenAI Developer Community says it "enables real-time decision-making by focusing Luna's intelligence on a specific set of user-defined questions with finite pre-defined answers," and that it "uses Luna to classify inputs, route requests, or choose an action from predefined answers."

From what OpenAI has described, a call has three parts:

- **Context**: text or images, such as a support ticket, a chat transcript, a product photo, or a screenshot an agent is looking at.
- **Your questions**: for example, "Which team should handle this?"
- **The allowed answers**: a fixed list for each question, such as billing, shipping, technical.

The API returns a selection from your list, and your code acts on it. OpenAI Developers used exactly that support example: send a request plus the teams it could go to, and get back the team.

That fits three kinds of work:

- **Classifying content**: intent, spam, policy category, refund vs. return.
- **Routing requests**: to a queue, a language team, or a support tier.
- **Choosing an agent's next step**: look up the order, ask a clarifying question, reply, or hand off to a person.

It is not a text generator. It is also unrelated to Decisions, the low-code automation platform at decisions.com, and to decisionapi.net.

## Decisions API status on October 6, 2026: what's published and what isn't

| Question | Public answer as of October 6, 2026 |
| --- | --- |
| Who can use it? | Limited preview. OpenAI Developers said access is "limited to selected API customers for testing." |
| When does it open to everyone? | On September 29, the DevDay recap said a broad release was "planned in the coming days." It hadn't happened by October 6. |
| What input does it take? | Text or images. |
| Which model runs it? | GPT-6 Luna. OpenAI hasn't said whether it is the standard `gpt-6-luna` or a tuned variant. |
| How fast is it? | OpenAI's Thibault Sottiaux posted that it is "tuned to be able to make decisions in less than a few hundreds of milliseconds end to end." A "150 ms" figure comes from a keynote slide described by [Firecrawl](https://www.firecrawl.dev/blog/openai-decisions-api-vs-jev) and from press coverage, not from OpenAI's docs. Neither has been independently benchmarked. |
| Does it return a confidence score? | Unknown. [The New Stack](https://thenewstack.io/openai-decision-api-luna) reports confidence scores; no OpenAI page or post confirms one. |
| Request and response schema, SDK method, model ID | Not published |
| Price and billing unit | Not published. The [API pricing page](https://developers.openai.com/api/docs/pricing) has no Decisions API row. |
| Rate limits, questions per call, answers per question, image limits, data residency | Not published |

Until a reference page exists, any Decisions API request body is a guess at the format. Reddit threads titled "Where's the Decisions API?" (posted around October 5) and "When will the Decision API be released?" (October 2) show developers still waiting for access.

## Can your key use it? What "Decision API is not enabled for this user" means

eesel AI's author called `POST https://api.openai.com/v1/decisions` on October 1 and again on October 2 with a standard key. Both times the response was HTTP 403:

```json
{
  "error": {
    "message": "Decision API is not enabled for this user.",
    "type": "invalid_request_error",
    "param": null,
    "code": null
  }
}
```

Nearby paths such as `/v1/decisions/create` returned 404, which eesel reads as a feature gate on a real route rather than a missing one. The 403 came back even for an empty body, which means the error says nothing about the request format.

To see where your own account stands, send the same empty request. It needs no schema:

```bash
curl -i -X POST https://api.openai.com/v1/decisions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

How to read the result:

- **403 with "not enabled for this user"**: your account isn't in the preview. Changing your code, key, or project settings won't fix it, and retries won't either.
- **404**: the path has moved. Check developers.openai.com for a Decisions API page.
- **Anything else**: something changed for your account. Without a published reference you still can't build a reliable request, so look for docs or preview material from OpenAI before writing code against it.

![Three rows mapping the empty-body check result to an action: 403 not enabled means ship on GPT-6 Luna now, 404 means find the new docs page, any other status means read the reference first](https://www.aifreeapi.com/posts/en/openai-decisions-api/img/decisions-403-check.webp)

No third-party gateway can sell you access. The endpoint is OpenAI's own and gated per OpenAI account.

## Wait or ship now? Decide by how fast each answer must arrive

For most uses, ship on GPT-6 Luna now. Waiting only makes sense when sub-second decisions are the whole point of the feature, and even then a working Luna version gives you something to compare against later.

| Your situation | What to do this week |
| --- | --- |
| Ticket, email, or content triage where a second or two doesn't matter | Ship Luna with a strict enum schema now. |
| Inputs are screenshots or photos | Ship Luna. It takes image input today. Image support is also what sets the Decisions API apart from text-only decision models such as Jev. |
| Live chat, or an agent loop that waits on many small choices | Ship Luna, measure latency on your own traffic, and treat Decisions API speed as the main reason to switch later. |
| Re-labeling a backlog, nothing user-facing | Run Luna through the Batch API at half the Standard price. |
| You're already in the preview | Test it, but keep the Luna path running until docs, price, and limits are public. |
| Text only, and you need per-option probabilities today | Also evaluate TypeSafe's Jev, a separate decision model that is generally available, text-only, and returns per-option probabilities. Check its price on TypeSafe's own site. |

Speed is the real gap. In eesel AI's test, Luna with a strict schema and reasoning set to `none` had a median of 1.46 s per decision, measured end to end from a laptop, and 2.33 s at medium reasoning effort. OpenAI's claim is "less than a few hundreds of milliseconds." For queue routing nobody notices the difference. An agent that makes 20 small choices per task waits about 30 seconds at 1.5 s each, which is where a faster endpoint would matter.

## Build the same decision on GPT-6 Luna with a strict enum schema

[GPT-6 Luna](https://developers.openai.com/api/docs/models/gpt-6-luna) (`gpt-6-luna`) supports Structured Outputs, image input, and `reasoning.effort` from `none` to `max`, through the Responses, Chat Completions, and Batch APIs. With [Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs) in strict mode, the model's output must match your JSON Schema. A schema whose only property is an `enum` therefore limits the answer to your list.

You need an API key with prepaid credits (see [how to get an OpenAI API key and what it costs](/en/posts/openai-api-key)), the key in `OPENAI_API_KEY`, and for the Python version, `pip install openai`. The examples follow the request shape in OpenAI's Structured Outputs guide. Run them on a few dozen labeled examples from your own data before trusting the labels.

### Request: one enum field with a needs_review answer

```bash
curl https://api.openai.com/v1/responses \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-luna",
    "reasoning": { "effort": "none" },
    "max_output_tokens": 50,
    "input": [
      {
        "role": "developer",
        "content": "Route the support request to exactly one queue. If it fits none of them, mixes several, or you cannot tell, answer needs_review."
      },
      {
        "role": "user",
        "content": "I was charged twice for order #4471."
      }
    ],
    "text": {
      "format": {
        "type": "json_schema",
        "name": "ticket_route",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "queue": {
              "type": "string",
              "enum": ["billing", "shipping", "technical", "needs_review"]
            }
          },
          "required": ["queue"],
          "additionalProperties": false
        }
      }
    }
  }'
```

The model's text output is a JSON object such as `{"queue":"billing"}`. Three schema rules from the guide trip people up: the root must be an object, every property must be listed in `required`, and every object needs `"additionalProperties": false`. A schema can hold up to 1,000 enum values in total, which is far more than a routing list needs.

`reasoning.effort: "none"` skips reasoning tokens, so it is the cheapest and fastest setting. Move to `low` only if your labeled set shows that `none` makes too many mistakes.

### Python: a decide() interface you can swap later

Keep the labels, the instructions, and the API call in one class, and let the rest of your app see only a `Decision`. When OpenAI publishes the Decisions API reference, you write one more class and change one line.

![Diagram: a support ticket with optional screenshot goes into decide(), backed by GPT-6 Luna now and the Decisions API later; billing, shipping and technical labels can act after a shadow-mode test, while needs_review, refusals and incomplete output go to a person](https://www.aifreeapi.com/posts/en/openai-decisions-api/img/luna-decider-review-path.webp)

```python
import base64
import json
import mimetypes
from dataclasses import dataclass
from typing import Optional, Protocol

from openai import OpenAI

QUEUES = ["billing", "shipping", "technical", "needs_review"]
FALLBACK = "needs_review"

INSTRUCTIONS = (
    "Route the support request to exactly one queue. If it fits none of them, "
    "mixes several, or you cannot tell, answer needs_review."
)

SCHEMA = {
    "type": "object",
    "properties": {"queue": {"type": "string", "enum": QUEUES}},
    "required": ["queue"],
    "additionalProperties": False,
}


@dataclass
class Decision:
    answer: str
    backend: str


class Decider(Protocol):
    def decide(self, text: str, image_path: Optional[str] = None) -> Decision: ...


class LunaDecider:
    def __init__(self, client: Optional[OpenAI] = None, model: str = "gpt-6-luna"):
        self.client = client or OpenAI()  # reads OPENAI_API_KEY
        self.model = model

    def decide(self, text: str, image_path: Optional[str] = None) -> Decision:
        content = [{"type": "input_text", "text": text}]
        if image_path:
            mime = mimetypes.guess_type(image_path)[0] or "image/png"
            with open(image_path, "rb") as f:
                b64 = base64.b64encode(f.read()).decode()
            content.append({"type": "input_image", "image_url": f"data:{mime};base64,{b64}"})

        response = self.client.responses.create(
            model=self.model,
            reasoning={"effort": "none"},
            max_output_tokens=50,
            input=[
                {"role": "developer", "content": INSTRUCTIONS},
                {"role": "user", "content": content},
            ],
            text={"format": {"type": "json_schema", "name": "ticket_route",
                             "strict": True, "schema": SCHEMA}},
        )

        # Incomplete output (for example, max_output_tokens reached) goes to review.
        if response.status != "completed":
            return Decision(FALLBACK, "luna:incomplete")
        message = next((item for item in response.output if item.type == "message"), None)
        part = message.content[0] if message and message.content else None
        # A safety refusal does not follow your schema, so it goes to review too.
        if part is None or part.type != "output_text":
            return Decision(FALLBACK, "luna:refusal")
        return Decision(json.loads(part.text)["queue"], "luna")


class DecisionsApiDecider:
    """Fill in once OpenAI publishes the Decisions API reference."""

    def decide(self, text: str, image_path: Optional[str] = None) -> Decision:
        raise NotImplementedError


if __name__ == "__main__":
    decider: Decider = LunaDecider()
    print(decider.decide("I was charged twice for order #4471."))
    # With a screenshot:
    # print(decider.decide("Customer says the app crashes here.", "crash.png"))
```

The `image_path` argument covers screenshots and photos. OpenAI's [API changelog](https://developers.openai.com/api/docs/changelog) notes that on September 25, 2026 it fixed an image-encoding bug that had degraded image understanding in GPT-6 Sol and Luna. If you evaluated Luna on images before that date, run the evaluation again.

### Through Chat Completions or an OpenAI-compatible gateway

Chat Completions takes the same schema under `response_format`. Use this form if your stack is built on Chat Completions or you call Luna through an OpenAI-compatible provider:

```python
response = client.chat.completions.create(
    model="gpt-6-luna",
    reasoning_effort="none",
    messages=[
        {"role": "system", "content": INSTRUCTIONS},
        {"role": "user", "content": "I was charged twice for order #4471."},
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {"name": "ticket_route", "strict": True, "schema": SCHEMA},
    },
)
queue = json.loads(response.choices[0].message.content)["queue"]
```

If you can't pay OpenAI directly, [laozhang.ai](https://docs.laozhang.ai/en/models) lists `gpt-6-luna` on its OpenAI-compatible `/v1/chat/completions` route at the same $0.10 input and $0.50 output per 1M tokens (pricing page updated September 24, 2026). Its docs note that "OpenAI-compatible" does not mean every client parameter is supported. Point `OpenAI(base_url="https://api.laozhang.ai/v1", api_key=...)` at it and send one test call to confirm the strict schema is enforced before you rely on it. This only covers the Luna workaround. It does not give you the Decisions API.

## Before a label sends, spends, or changes anything: add a review path

A strict schema guarantees a valid label, not a correct one. OpenAI's guide says outputs "can still contain mistakes," and that when the input is unrelated to the schema, the model will still try to fit it, which can produce a wrong label. That's why the schema above has a `needs_review` answer and the instructions say when to use it.

eesel AI's test shows where the risk sits. Across 20 support tickets, every setup picked the right queue 40 of 40 times. On "is this safe to auto-reply?", Luna with no reasoning got 33 of 40. It is one small test by a vendor that sells helpdesk automation, but it matches a useful rule: routing is the easy call, and deciding whether to act is the hard one.

For any decision that sends a message, spends money, or changes data:

1. **Give every enum an escape answer** (`needs_review`, `other`, or `unsure`) and send it to a person.
2. **Treat refusals and incomplete responses the same way.** The `LunaDecider` above already does.
3. **Run in shadow mode first.** Log the model's answer next to the human decision on real traffic, measure the error rate per label, and only then let low-risk labels act automatically.
4. **Log enough to re-check later**: the input, the label, the model, the reasoning effort, the instructions version, and the final outcome. You'll need this when you compare against the Decisions API.
5. **Don't build thresholds on a confidence score.** This Luna setup doesn't return one, and no OpenAI document confirms that the Decisions API will.

## What a GPT-6 Luna decision costs: about $47.50 per million at 400 input tokens

The Decisions API has no published price, so the only first-party yardstick is GPT-6 Luna's own rate card. As of October 6, 2026, the [Luna model page](https://developers.openai.com/api/docs/models/gpt-6-luna) lists Standard rates of $0.10 per 1M input tokens and $0.50 per 1M output tokens, with Batch and Flex at 50% of Standard.

Cost per decision = input tokens × $0.10 / 1,000,000 + output tokens × $0.50 / 1,000,000

| Assumed tokens per decision | Tier | Per decision | Per 1,000 | Per 1,000,000 |
| --- | --- | ---: | ---: | ---: |
| 400 input + 15 output | Standard | $0.0000475 | $0.0475 | $47.50 |
| 800 input + 15 output | Standard | $0.0000875 | $0.0875 | $87.50 |
| 400 input + 15 output | Batch (asynchronous) | $0.00002375 | $0.02375 | $23.75 |

The token counts are assumptions for a short text instruction, one ticket, and a one-word JSON answer. Replace them with your own numbers:

- **Images add input tokens** depending on their size. Log `response.usage.input_tokens` and `response.usage.output_tokens` for a sample of real requests and use the averages.
- **Reasoning effort adds output tokens.** Reasoning tokens bill at the output rate. In eesel AI's test the same routing job cost about $0.047 per 1,000 tickets at `none` and $0.089 at medium.
- **Batch is asynchronous**, so it suits backlogs and nightly re-labeling, not live routing.

Rate limits cap throughput as well. At Tier 1, Luna allows 500 requests per minute and 500,000 tokens per minute. With 400-token decisions, the request limit binds first, at 500 decisions per minute or about 720,000 a day.

When OpenAI prices the Decisions API, it may bill per call, per question, or per token. Run the same arithmetic on its rate and compare it with your logged Luna cost. To see how Luna compares with the larger Sol model for the same workload, see [GPT-6 Luna vs. Sol pricing: calculate the cost of your workload](/en/posts/gpt-6-luna-vs-sol-price).

## When to switch to the Decisions API: six signals to watch

Re-evaluate as soon as any of these appear:

1. **A Decisions API page on developers.openai.com** with a request and response reference. That is the first point at which you can write `DecisionsApiDecider`.
2. **Your key stops returning the 403** from the empty-body check above.
3. **A published price and billing unit.** Convert it to cost per million decisions with your real token or call counts and compare it with your Luna logs.
4. **Documented limits that fit your schema**: questions per call, answers per question, image size, and rate limits.
5. **A documented confidence or probability field.** Only then is it safe to add "act above X, review below X" rules.
6. **Latency measured from your own servers** that beats your Luna median and tail by enough to matter for your users.

To switch, run both deciders on the same traffic in shadow mode, compare their agreement and their error rate on your labeled set, and then change the one line that picks the decider.

## OpenAI Decisions API FAQ

### When will the OpenAI Decisions API be released?

There is no date. On September 29, 2026, OpenAI's DevDay recap said a "broad release planned in the coming days." As of October 6, 2026, the endpoint was still a limited preview with no docs page.

### How much does the Decisions API cost?

OpenAI hasn't published a price or billing unit. The closest first-party yardstick is GPT-6 Luna at $0.10 input and $0.50 output per 1M tokens, which works out to $47.50 per million decisions at an assumed 400 input and 15 output tokens. That is Luna's price, not a Decisions API price.

### Is the Decisions API available in ChatGPT?

Not as announced. OpenAI introduced it as an API for developers, listed with its other API launches, and nothing in the announcement describes a ChatGPT feature.

### How does the Decisions API compare with TypeSafe's Jev?

Jev, launched on September 15, 2026, is a separate model built for the same kind of fixed-answer decisions. It is generally available, accepts text only, and returns a probability for each option. The Decisions API accepts images but is in limited preview, with no public price, docs, or confirmed confidence output.

### Does the Decisions API return a confidence score?

It isn't documented. The New Stack reported confidence scores, but no OpenAI page or post confirms a confidence field. Don't design approval thresholds around one until the reference is published.

### Can I get the Decisions API through a third-party gateway?

No. It is OpenAI's own endpoint, gated per OpenAI account. Gateways can only offer the Luna-based workaround, and you should check with one test call that they enforce strict JSON schemas.
