OpenAI's Decisions API (POST /v1/decisions, GPT-6 Luna Decisions, public beta since 2026-10-06) and the System One request that TypeSafe's Jev introduced say the same things in different words. If you already have code for one, the other is a mechanical translation. This post maps the two field by field, lists the two gotchas that silently give wrong answers, and shows how to send OpenAI-shaped requests to the other twelve decision models.
Checked 2026-10-08 against OpenAI's API reference and OpenRouter's /api/alpha/decisions.
Field by field
OpenAI /v1/decisions
|
System One (Jev and the rest) |
|---|---|
input: a string, or user messages with input_text / input_image parts |
state: a string, a JSON object, or text and image parts |
questions: an array [{type, name, ...}]
|
questions: an object { id: {type, ...} }
|
predicate {instructions}
|
noul {instructions, criteria: {true, false}}
|
choice {choices: [{value, description}]}
|
choice {criteria: {value: description}}
|
score {levels: [{label, description}]}
|
score {criteria: ["label: description", ...]}
|
answers: an array in question order
|
answers: an object keyed by your ids |
probability / choice / score
|
noul / choice / score
|
refusal |
a question that comes back without an answer |
Pricing has the same shape on both sides: input tokens only. GPT-6 Luna Decisions is $0.10 per million input tokens, Jev $0.042, and no decision model I tested bills output.
Two gotchas that fail silently
Images. OpenAI takes input_image parts carrying a data URL. OpenRouter's Decisions API reads images only as chat-style image_url parts. Send it an input_image part and it does not error — it answers from the base64 read as text. In my test a solid red square came back "blue" from three image models until the part type was changed.
Option caps. Not every model takes every question. Upstage's Solar Decide accepts at most 26 choice options and Together's Tev1 at most 20; Respan's Span-01 models answer yes/no only. Route a 77-intent classifier to one of those and the request is refused.
Translating, in about 30 lines
type OaiQ =
| { type: "predicate"; name?: string; instructions: string }
| { type: "choice"; name?: string; instructions: string; choices: { value: string; description?: string }[] }
| { type: "score"; name?: string; instructions: string; levels: { label: string; description?: string }[] };
export function toSystemOne(input: string, questions: OaiQ[]) {
const q: Record<string, unknown> = {};
questions.forEach((x, i) => {
const id = `q${i}`;
if (x.type === "predicate") q[id] = { type: "noul", instructions: x.instructions, criteria: { true: "Yes", false: "No" } };
if (x.type === "choice") q[id] = { type: "choice", instructions: x.instructions,
criteria: Object.fromEntries(x.choices.map((c) => [c.value, c.description || c.value])) };
if (x.type === "score") q[id] = { type: "score", instructions: x.instructions,
criteria: x.levels.map((l) => (l.description ? `${l.label}: ${l.description}` : l.label)) };
});
return { state: input, questions: q };
}
// Answers come back keyed q0, q1, ... — read them in that order to rebuild OpenAI's array.
POST the result, plus a model, to https://openrouter.ai/api/alpha/decisions and it works for any of the thirteen models listed by GET https://openrouter.ai/api/v1/models?output_modalities=decisions.
Or keep the OpenAI SDK
If you would rather not translate at all, I put an OpenAI-compatible endpoint in front of all thirteen on my site, so the official SDK works unchanged:
import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://jev-agent.com/api/v1", apiKey: process.env.JAGENT_KEY });
const res = await client.decisions.create({
model: "liquid/d1", // or jev-latest, gpt-6-luna, cloudflare/clef, ...
input: "I was charged twice for September and I'm cancelling on Friday unless it's refunded.",
questions: [
{ type: "choice", name: "team", instructions: "Which team should handle this?",
choices: [{ value: "billing" }, { value: "technical" }] },
{ type: "predicate", name: "churn", instructions: "The customer threatens to cancel." },
],
});
Which model to pick depends on the decision: on a simple gate they all land within a few points; with dozens of options and an action triggered by a confidence threshold, they don't. I measured all thirteen on the same 633 items — accuracy, the rate of confident wrong answers, latency and cost — in this write-up, with raw data in jev-measured.
I run jev-agent.com (Jagent), an independent site; not affiliated with OpenAI, TypeSafe or OpenRouter.
Top comments (0)