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

# Decisions API

> Typed answers about text — routing, tagging, yes/no, scores — from the open OpenDecision models.

`POST /v1/decide` answers questions about text. You send one text (or up to 64) and
the questions you want answered; each question is a **choice** between options, a
**multilabel** tag set, a **bool**, or a **score** on an integer range. The reply is,
per text and question, the best option, a probability for every option, and for
scores the expected value.

It is the hosted version of the open [OpenDecision](https://github.com/tokz-labs/OpenDecision)
models, which you can also run yourself.

> [!NOTE]
>
> This runs a model. The text is sent to Tokz and read by an OpenDecision model; it
> is not stored or logged, and only counters are kept. Do not send what you would
> not send to a hosted model. Building a [fine tune](https://docs.tokz.si/fine-tune.md#your-text) is different:
> that text goes to the services that train it.

## A request

```bash cURL theme={null}
curl https://api.tokz.si/v1/decide \
  -H "Authorization: Bearer $TOKZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": "I was charged twice for my May invoice and the app keeps logging me out.",
    "decisions": {
      "queue":    {"type": "choice", "question": "Which team should handle this ticket?",
                   "options": ["billing", "technical", "account", "sales"]},
      "tags":     {"type": "multilabel", "options": ["double_charge", "login_issue", "refund_request", "outage"]},
      "urgent":   {"type": "bool"},
      "priority": {"type": "score", "low": 1, "high": 5}
    }
  }'
```

```ts TypeScript theme={null}
import { Tokz } from "@tokz/sdk";

const tokz = new Tokz({ apiKey: process.env.TOKZ_API_KEY! });

const { results, usage } = await tokz.decide({
  inputs: "I was charged twice for my May invoice and the app keeps logging me out.",
  decisions: {
    queue: {
      type: "choice",
      question: "Which team should handle this ticket?",
      options: ["billing", "technical", "account", "sales"],
    },
    tags: { type: "multilabel", options: ["double_charge", "login_issue", "refund_request", "outage"] },
    urgent: { type: "bool" },
    priority: { type: "score", low: 1, high: 5 },
  },
});
```

```python Python theme={null}
# pip install tokz
import os
from tokz import Tokz

tokz = Tokz(api_key=os.environ["TOKZ_API_KEY"])

out = tokz.decide(
    "I was charged twice for my May invoice and the app keeps logging me out.",
    {
        "queue": {
            "type": "choice",
            "question": "Which team should handle this ticket?",
            "options": ["billing", "technical", "account", "sales"],
        },
        "tags": {"type": "multilabel", "options": ["double_charge", "login_issue", "refund_request", "outage"]},
        "urgent": {"type": "bool"},
        "priority": {"type": "score", "low": 1, "high": 5},
    },
)
results, usage = out["results"], out["usage"]
```

```json theme={null}
{
  "id": "dec_3f9a...",
  "model": "opendecision-large-packed",
  "results": [
    {
      "queue":    { "type": "choice", "best": "billing", "selected": ["billing"],
                    "policy": { "billing": 0.81, "technical": 0.14, "account": 0.04, "sales": 0.01 },
                    "value":  { "billing": 0.93, "technical": 0.41, "account": 0.12, "sales": 0.02 } },
      "urgent":   { "type": "bool", "best": "no", "selected": ["no"],
                    "policy": { "yes": 0.2, "no": 0.8 }, "value": { "yes": 0.2, "no": 0.8 } },
      "priority": { "type": "score", "best": "3", "selected": ["3"], "score": 3.2,
                    "policy": { "1": 0.05, "2": 0.2, "3": 0.4, "4": 0.25, "5": 0.1 },
                    "value":  { "1": 0.1, "2": 0.3, "3": 0.5, "4": 0.3, "5": 0.1 } }
    }
  ],
  "usage": { "billed_tokens": 256, "cost_usd": 0.0000064 }
}
```

The numbers above only show the shape. `policy` is the distribution over the options
(it sums to 1); `value` is the per-option probability that the option is correct, and
is what `multilabel` thresholds. Options can be strings or `{"id", "name", "description"}`;
the description is read by the model, so use it to say what an option means.

## Models and prices

| Model | USD / 1M billed tokens | Suite macro-F1 |
| - | - | - |
| `opendecision-small` | \$0.025 | 79.3 |
| `opendecision-large-packed` (default) | \$0.025 | 87.2 |
| `opendecision-large` | \$0.035 | 87.9 |

`GET /v1/decide/models` returns the live list. Suite macro-F1 is the average over AG News,
CLINC150, IMDb, Rotten Tomatoes and XNLI in the technical report. It describes
classification over label sets of the kind the models were trained on; on label sets
they have not seen, some other open models score higher, so test on your own data.

`model` also takes the name of a [fine tune](https://docs.tokz.si/fine-tune.md) your organization owns. Such a
model already knows its question and labels, so the request has no `decisions`.

## What is billed

Input only; answers are free. A **billed token** is a token of the text plus the
question, read once per 16 options, plus the option tokens. For a question with up to
16 options this is just the number of tokens you send. Questions with more than 16
options are billed at 3×, because they cost about that much more to serve.

Every request bills at least **256 tokens**. Serving cost is mostly per request, so
send several texts in one call (up to 64) when you can: a batch of short texts costs
the same per token as one long one.

Cost is billed tokens at the model's price, drawn from your prepaid credit (see
[Billing](https://docs.tokz.si/billing.md)). You are charged only for a request that succeeds: a 4xx or 5xx
costs nothing. At a zero balance `POST /decide` returns `402` with
`insufficient_credits`.

## Limits

| | |
| - | - |
| Texts per request | 64, each up to 20,000 characters |
| Questions per request | 16 |
| Options per question | 2 to 256, unique ids |
| Score range | 2 to 256 values |
| Body | 4 MiB |

## Errors

| Status | `error` | Meaning |
| - | - | - |
| 400 | `invalid_request`, `unknown_model` | The body is malformed; `message` says what to fix |
| 401 | | Missing or revoked key |
| 402 | `insufficient_credits` | No credit left |
| 429 | | Per-key rate limit |
| 502 | `decide_upstream_error` | The model service did not answer; retry |
| 503 | `decide_busy`, `decide_unavailable` | Model service saturated, or not enabled on this deployment |

A `429` or `503` can carry `Retry-After` in seconds. Fine tunes have a few more errors of
their own: see [Fine Tune](https://docs.tokz.si/fine-tune.md#errors).

## SDKs

`decide()` ships in **`@tokz/sdk` 0.5+** (`npm i @tokz/sdk`) and the Python package
**`tokz` 0.4+** (`pip install tokz`, sync `Tokz` and async `AsyncTokz`). Both send the
request above, return typed results, raise `TokzInsufficientCreditsError` on `402`, and
never retry, since a retry could bill twice. `listDecisionModels()` /
`list_decision_models()` return the catalog. See [TypeScript](https://docs.tokz.si/sdk/typescript.md) and
[Python](https://docs.tokz.si/sdk/python.md). Calling a fine tune by name needs `@tokz/sdk` 0.7+ or `tokz` 0.6+.

Send several texts in one call (up to 64) when you can: every request bills at least 256
tokens, and a batch shares one model pass.

## Usage

`GET /v1/decide/usage?days=30` returns the key's requests, texts, decisions, billed
tokens and cost, by day and by model. In the dashboard, **Usage** shows the same for the
whole organization, and **Playground** runs requests against one of your keys.


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