Drex guides

OpenAI-compatible decisions

Call Drex through the OpenAI SDKs, LiteLLM or Vercel AI Gateway with POST /v1/decisions, OpenAI's Decisions format on the System One pipeline.

POST /v1/decisions answers the same questions as POST /v1/systemone, in the wire format of OpenAI's Decisions API. A client built for that API needs only a base URL and a model change: the same nace_sk_ key, funding, rate limits, validation and billing apply, and the request reaches the model as the same bytes a System One request would. Use it when your code already speaks OpenAI's Decisions shape. New integrations that want typed answers keyed by name can use the Nace SDKs and /v1/systemone directly.

Base URL and models

Point the client at https://console.nace.ai/v1 and name a Drex model. drex-max and drex-max-v1.1 read text and images; drex-v2.0 and drex-latest read text. The Models reference lists them. model resolves as on /v1/systemone: a registered id or alias is served as named, no model is served like drex-latest, and any other name, gpt-6-luna and a mistyped drex- name included, returns 422 with code: model_not_found and param: model.

OpenAI TypeScript SDK
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://console.nace.ai/v1", apiKey: process.env.NACE_API_KEY });

const { answers, usage } = await client.decisions.create({
  model: "drex-v2.0",
  input: "I was charged twice for my March invoice. Please refund one of the charges.",
  questions: [
    { type: "predicate", name: "wants_refund", instructions: "Is the customer asking for a refund?" },
    { type: "choice", name: "topic", instructions: "Which topic is it?", choices: [{ value: "billing" }, { value: "shipping" }, { value: "other" }] },
    { type: "score", name: "urgency", instructions: "How urgent is it?", levels: [{ label: "low" }, { label: "medium" }, { label: "high" }] },
  ],
});
OpenAI Python SDK
from openai import OpenAI

client = OpenAI(base_url="https://console.nace.ai/v1", api_key=os.environ["NACE_API_KEY"])

decision = client.decisions.create(
    model="drex-v2.0",
    input="I was charged twice for my March invoice. Please refund one of the charges.",
    questions=[
        {"type": "predicate", "name": "wants_refund", "instructions": "Is the customer asking for a refund?"},
        {"type": "choice", "name": "topic", "instructions": "Which topic is it?", "choices": [{"value": "billing"}, {"value": "shipping"}, {"value": "other"}]},
    ],
)

LiteLLM reaches Drex through its OpenAI provider: a model entry openai/drex-max with api_base: https://console.nace.ai/v1 and your key as api_key. Vercel AI Gateway's /v1/decisions route takes the same base URL change.

How the request maps

Each OpenAI field becomes its System One counterpart before validation, so every rule on Questions, State and Drex Max applies unchanged.

OpenAISystem OneNotes
input as a stringstateSent as is.
input as user messagesstateText parts, in order across messages, joined with a blank line. A single input_json part with no text is sent as structured JSON state; next to text it is serialized in place. input_json data is an object or an array of objects, as in OpenAI's schema. Other roles and tool items return 422.
input_image partsimages[]In part order across messages. The model sees them as Image 1, Image 2 and so on, before the text, so refer to them that way. detail (low, high, auto, original or null, as in OpenAI's schema) is accepted and ignored, because Drex has one image profile.
predicatenoulprobability is the probability of yes.
choice with choices[].valuechoice with criteriaA value comes back as sent, so true stays a boolean. A boolean is the lowercase label true or false, so a string equal to that label ("true") in the same question returns 422 whose param is the later choice, such as questions[0].choices[1].value; "True" is a different string and its own option. 2 to 255 choices, each unique, as in OpenAI's schema: one choice, or a repeated value, returns 422.
score with levels[]score with criteria2 to 10 levels. A level's description is shown to the model with its label; probabilities[].label returns the label alone.
namethe question's keyEchoed on the answer; null when absent. OpenAI's schema doesn't require names to be unique, so a repeated name is accepted; answers come back in question order.
safety_identifierdroppedA string or null of up to 128 characters, as in OpenAI's schema. Drex neither forwards nor stores it.
prompt_cache_key, prompt_cache_options, prompt_cache_breakpointdroppedChecked against OpenAI's schema (prompt_cache_key up to 64 characters; mode implicit or explicit; ttl 30m; a breakpoint's mode explicit) and ignored: Drex has no prompt cache.

Images

Images are data URLs only (data:image/png, data:image/jpeg or data:image/webp, up to 16 MiB decoded and 32 MiB together); Drex does not fetch image URLs, and an https:// image_url returns 422 naming that part. Up to 8 per request, on drex-max and drex-max-v1.1 only: an image sent to drex-v2.0 returns 422 with code: invalid_value and param naming the first image part, the same refusal /v1/systemone gives as images: images require drex-max or drex-max-v1.1. Inline images count toward the 4 MiB body limit.

Response

{
  "model": "drex-v2.0",
  "answers": [
    { "type": "predicate", "name": "wants_refund", "probability": 0.9868 },
    { "type": "choice", "name": "topic", "choice": "billing", "confidence": 0.986, "probabilities": [{ "value": "billing", "probability": 0.9895 }, { "value": "shipping", "probability": 0.0056 }, { "value": "other", "probability": 0.0049 }] },
    { "type": "score", "name": "urgency", "score": 1.53, "confidence": 0.72, "probabilities": [{ "value": 0, "label": "low", "probability": 0.16 }, { "value": 1, "label": "medium", "probability": 0.15 }, { "value": 2, "label": "high", "probability": 0.69 }] }
  ],
  "usage": {
    "input_tokens": 106,
    "output_tokens": 212,
    "total_tokens": 318,
    "input_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 0 },
    "output_tokens_details": { "reasoning_tokens": 0 }
  },
  "request_id": "req_<32 hex characters>"
}

answers is in question order. usage.input_tokens is what Drex bills, image tokens included; the detail counts are always zero. request_id is Drex's; quote it in support requests. Drex's models answer every question, so no answer is a refusal today; the type is in OpenAI's contract and a client should keep handling it.

Errors

Every error keeps Drex's error.type and HTTP status (see Errors and retries) and adds OpenAI's error.code and error.param. The OpenAI SDKs raise their usual classes: a 422 is UnprocessableEntityError with code, param and Drex's issues, each issue's path a param.

HTTPerror.typeerror.codeerror.param
401authentication_errorinvalid_api_keynull
402insufficient_credit, payment_requiredinsufficient_quotanull
422invalid_request_errorinvalid_value; model_not_found for a model that isn't a registered id or alias (gpt-6-luna, a mistyped drex- name), or that names a registered model that isn't available yet; context_length_exceeded when the request is over the model's token limit, with Drex's own messageThe field at fault, as a path into the request: input, input[0].content[1].image_url, questions[2].levels, model. null for a body that isn't JSON.
429rate_limit_errorrate_limit_exceedednull
500internal_errorserver_errornull
529overloadedoverloadednull
A 422
{
  "error": {
    "type": "invalid_request_error",
    "message": "questions[2].levels: must have 2 to 10 levels",
    "code": "invalid_value",
    "param": "questions[2].levels",
    "issues": [{ "path": "questions[2].levels", "message": "must have 2 to 10 levels" }]
  },
  "request_id": "req_<32 hex characters>"
}

Not supported

Streaming (OpenAI's Decisions API has none), per-question images or input_json inside instructions (a non-string instructions returns 422 naming questions[i].instructions), image URLs, more than 8 images, and messages from roles other than user.

On this page