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.
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" }] },
],
});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.
| OpenAI | System One | Notes |
|---|---|---|
input as a string | state | Sent as is. |
input as user messages | state | Text 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 parts | images[] | 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. |
predicate | noul | probability is the probability of yes. |
choice with choices[].value | choice with criteria | A 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 criteria | 2 to 10 levels. A level's description is shown to the model with its label; probabilities[].label returns the label alone. |
name | the question's key | Echoed 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_identifier | dropped | A 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_breakpoint | dropped | Checked 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.
| HTTP | error.type | error.code | error.param |
|---|---|---|---|
| 401 | authentication_error | invalid_api_key | null |
| 402 | insufficient_credit, payment_required | insufficient_quota | null |
| 422 | invalid_request_error | invalid_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 message | The 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. |
| 429 | rate_limit_error | rate_limit_exceeded | null |
| 500 | internal_error | server_error | null |
| 529 | overloaded | overloaded | null |
{
"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.
Drex Max
Call Drex Max, the most accurate Drex model, with text or images, and the limits that differ from the other models.
Browser runs
Give an agent a task and a website; it browses in a cloud browser and returns an answer. How to start, follow and cancel a run, what it may browse, and what it costs.