> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ndi.nace.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Drex (Decision Model)

> Drex, NDI's decision model, answers typed questions about a state in one System One call, with probabilities

**Drex** is NDI's decision model. **System One** is the topology it runs in:
one synchronous call in which Drex answers every question about a state, with no
agent loop, job or workspace. The endpoint, SDK resource, CLI command and MCP
tool are named `systemone` after it.

Returns the answers directly: no job, no workspace, nothing stored. Send a
**state** (the situation, as text or any JSON value) and the **questions** to
decide about it, keyed by name. Drex answers every question in
one call and returns a probability for each outcome.

Each question has a `type`:

| Type | Asks | Answer |
| - | - | - |
| `noul` | a yes/no statement, from `instructions` and optional `criteria.true` / `criteria.false` | `noul`: probability the statement is true |
| `choice` | a pick among named options in `criteria` (name → optional description) | `choice`, its `confidence`, and every option's `probabilities` |
| `score` | a position on an ordered scale, `criteria` lowest level first | `score` (expected level index), `legend`, `probabilities` by level index, `confidence` |

`confidence` is Drex's average confidence in the answer. It tracks
the highest value in `probabilities` but is a different number, so do not
compute one from the other.

The `probabilities` of a `choice` or a `score` add up to 1. A score is an
expected value, so `legend[round(score)]` names the level nearest it, which is
not always the most likely level. For that, take the highest entry in
`probabilities`.

```bash theme={"dark"}
curl -s -X POST "$NDI_BASE_URL/v1/systemone" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"state":"Invoice INV-1844 bills 240 bearings at £4.80; the purchase order allows 200 at £4.15.","questions":{"matches_po":{"type":"noul","instructions":"Does the invoice match its purchase order?"},"exception":{"type":"choice","instructions":"What is the main exception?","criteria":{"none":null,"price_variance":"A unit price is above the purchase order.","quantity_variance":"A quantity is above the purchase order."}},"disposition":{"type":"score","instructions":"How should accounts payable treat it?","criteria":["pay","review","hold","reject"]}}}'
```

```json theme={"dark"}
{
  "model": "nace-ai/drex-v1.5",
  "answers": {
    "matches_po": { "type": "noul", "noul": 0.04 },
    "exception": {
      "type": "choice",
      "choice": "price_variance",
      "confidence": 0.66,
      "probabilities": { "none": 0.02, "price_variance": 0.71, "quantity_variance": 0.27 }
    },
    "disposition": {
      "type": "score",
      "score": 1.3,
      "legend": ["pay", "review", "hold", "reject"],
      "probabilities": { "0": 0.03, "1": 0.64, "2": 0.30, "3": 0.03 },
      "confidence": 0.61
    }
  },
  "usage": { "input_tokens": 212, "output_tokens": 186 },
  "evaluation_time_ms": 184.0,
  "request_id": "4f1c…"
}
```

`model` names the decision model as this deployment calls it, and `usage`
token counts may be `null` when the model does not report them.

## Limits and input rules

* A call carries 1 to 512 questions. A `choice` lists 1 to 255 options, and a
  `score` 1 to 255 levels.
* The state and questions together must fit the decision model's context. A
  longer request is refused with `422` at path `state`.
* Question names are trimmed, and each answer comes back under the trimmed
  name. A blank name is refused.
* Unknown fields are refused, except `model`, which is accepted and ignored: the
  deployment chooses the decision model.
* A NUL character (`\u0000`) anywhere in the body is refused.
* Nothing is stored, so sending the same call again is safe. The SDKs do not
  retry it on their own; retry a `429` after `Retry-After`, and a `503`.

## Errors

* `401 unauthorized` — the `X-API-Key` header is missing or the key is invalid.
  This endpoint does not accept `Authorization: Bearer`.
* `422 invalid_request` — the body does not match the schema, or the state and
  questions are too long for the decision model. Besides the usual
  `detail.errors`, the error carries `detail.issues`: one `{path, message}` per
  refused field, by dotted path (`state`, `questions.exception.criteria`).
  `detail.errors[].loc` starts with `body` and includes the question's type
  (`["body", "questions", "exception", "choice", "criteria"]`); `detail.issues`
  paths leave both out.
* `501 not_implemented` — this deployment has no decision model.
* `429 rate_limited` — the account's request or concurrency budget is spent.
* `503 upstream_unavailable` — the decision model is unavailable or did not
  answer within 45 seconds; retry.

See [Errors](/concepts/errors).

| Path | SDK |
| - | - |
| `POST /v1/systemone` | `client.systemone.evaluate` (Python and TypeScript), `ndi systemone` (CLI), `evaluate_systemone` (MCP) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.