# Decisions

The decisions routes take a `state` and up to 32 typed questions about it, and answer each one in a fixed shape: a probability for `noul`, the chosen category and a probability per category for `choice`, and a position on your scale for `score`. No public model on llm.buzz answers them.

## Availability

`GET https://api.llm.buzz/api/v1/models?output_modalities=decisions` lists the models that answer decisions. Today it lists none, so a decisions request answers an error.

```bash
curl -s "https://api.llm.buzz/api/v1/models?output_modalities=decisions"
```

```json
{"object": "list", "data": [], "total_count": 0, "links": {"next": null}}
```

A model that answers decisions appears under that filter, and under `output_modalities=all`. [Choosing an API](choosing-an-api.md#find-a-model-for-an-api) lists the filters for every kind of model.

## Routes

| Route | What it is |
|---|---|
| `POST https://api.llm.buzz/api/v1/systemone` | TypeSafe's System One route. A model name without a `/` is read as `typesafe/<name>`. |
| `POST https://api.llm.buzz/api/alpha/decisions` | The route OpenRouter's SDKs call as `alpha.decisions`. They build it from the host alone, so give that one call the origin of `https://api.llm.buzz/api/v1` as its server URL, the same address without `/api/v1`. Model names are taken as written. |

Both routes take the same body and answer in the same shape, which follow TypeSafe's System One and OpenRouter's Decisions API. They take your inference key as a bearer token ([Authentication](authentication.md)); a management key answers 403 `management_key_not_allowed`. A browser page can call both: their preflight needs no key ([Browser access](api-reference.md#browser-access)).

## The request

Three fields are required, and the body is not chat: it has no messages, tools or generation settings.

| Field | What llm.buzz does |
|---|---|
| `model` | Required: a model that answers decisions. |
| `state` | Required: what the questions are about. Text, a JSON object or a JSON array; objects and arrays keep their structure. |
| `questions` | Required: 1 to 32 questions, each under an ID you choose. The ID comes back in `answers`. A question has a `type`, its `instructions` (text, an object or an array) and, for some types, `criteria`: [Question types](#question-types). |
| `provider` | Read only for `zdr` and `data_collection`, which keep the request on providers that meet the policy ([Data policy](models-and-routing.md#data-policy)). Every other key is ignored. |
| `session_id`, `trace`, `user` | Dropped. |
| Any other field | Refused before any provider is called, `stream` and chat fields included. |

## Question types

| Type | What it asks | `criteria` | The answer holds |
|---|---|---|---|
| `noul` | The probability that the statement in `instructions` holds. | Optional: an object with descriptions for `true` and `false`. | `noul`, a probability from 0 to 1. |
| `choice` | Which of your categories fits. | 2 to 64 category names, each with a description (text, an object or an array) or `null`. | `choice`, the category chosen; `confidence`; `probabilities`, one per category, keyed by your category names. |
| `score` | How the state rates on a scale whose steps you list in order. | A list of 2 to 10 descriptions, one per step, in order. | `score`, `confidence`, `legend`, and `probabilities` with one entry per step, keyed by the step's zero-based position written as a string. |

## The answer

The body carries `id`, the `model` you asked for, and `answers`: one entry under each of your question IDs, with its `type` and the fields above. `usage` holds `input_tokens` and `output_tokens`, the counts the provider reported, and `usage.cost`, the request's cost in US dollars at your rate as a JSON number. `cost` is left out when any part of it is unknown. The body has no `provider` key: `x-gateway-provider` in the response headers names the provider that answered, when it has a display name.

These are decision values, not assistant text. llm.buzz returns the provider's probabilities and scores as the provider gave them and never recomputes or normalizes them. It checks each answer before it reaches you: probabilities and confidence fall between 0 and 1, a distribution sums to 1 and the chosen category is the most probable (both within rounding), and the keys match your criteria. Only the validated fields come back, and any other metadata from the provider is left out.

## Limits

- 1 to 32 questions per request, and 1 to 256 bytes for a question ID or a category name.
- 262,144 bytes for the body. Nested data may go at most 64 levels deep.
- An answer is buffered and never streamed.
- An `Idempotency-Key` is ignored: sending the same request again runs it again as a request of its own.
- Not offered: `box` questions, and image, audio or video state.

## Errors

Errors come in OpenRouter's envelope: `error.metadata.gateway_code` says what went wrong and `metadata.param` names the field at fault. [Errors](errors.md) lists the key, balance and model errors. Two are specific to these routes, and both are refused before any provider is called:

- A body that fails the decision schema answers 400 `invalid_parameter` with `param` set to `body`. The message lists the fields the route accepts.
- A model that serves no decisions, which is every public model today, answers 400 `unsupported_capability` with `param` set to `model`.
