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

# Decisions

> Ask a model a typed question and get a calibrated probability back — yes/no, pick-one, or score — with Cloudflare's Clef decision models, on your AI Reserve key and wallet, billed per input token.

The gateway exposes decision models under `/v1/decisions`, with the same API key, rate limits,
wallet, and spend caps as every other route. Behind it sit Cloudflare's open-weight
[Clef](https://developers.cloudflare.com/workers-ai/models/clef/) models: you send a **state**
(text, JSON, or images) and a schema of typed **questions**, and get back a probability for every
allowed answer of every question in one forward pass. There is no free-form text to parse, no
reasoning tokens to wait for, and no prompt engineering to coax out valid JSON — the model can
only answer in the shape you declared.

Use it for the parts of an agent that are classification, routing, triage, moderation, or scoring
rather than writing: "is this ticket urgent", "which team owns it", "how severe is the impact",
"does this reply follow the policy". A decision is a few hundred milliseconds and a fraction of a
cent, so you can ask it on every turn.

You never create a Cloudflare account or hold a Cloudflare token. AI Reserve holds one account,
each decision is billed to your wallet at the published per-token rate, and every decision appears
in your usage analytics under the model `clef` or `clef-flash`.

> [!NOTE]
>
> **Jev / System One compatible.** The request and response bodies are the System One decision
> API, so an existing Jev integration moves over by pointing at
> `https://api.aireserve.com/v1/decisions` with your AI Reserve key and setting `model` to `clef`
> or `clef-flash`.

## Quickstart

```bash theme={"dark"}
curl -s https://api.aireserve.com/v1/decisions \
  -H "Authorization: Bearer $AIRESERVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "clef-flash",
    "state": "Checkout has been failing for every customer for the last hour.",
    "questions": {
      "urgent":   { "type": "noul",   "instructions": "Is this support request urgent?" },
      "team":     { "type": "choice", "instructions": "Which team should handle this request?",
                    "criteria": { "billing": "Payments, invoices, and refunds",
                                  "technical": "Outages, errors, and configuration",
                                  "sales": "Plans and upgrades" } },
      "severity": { "type": "score",  "instructions": "How severe is the customer impact?",
                    "criteria": ["No impact", "Minor", "Major", "Critical"] }
    }
  }'
```

```json theme={"dark"}
{
  "model": "clef-flash",
  "answers": {
    "urgent": { "type": "noul", "noul": 0.97 },
    "team": {
      "type": "choice",
      "choice": "technical",
      "confidence": 0.94,
      "probabilities": { "billing": 0.05, "technical": 0.94, "sales": 0.01 }
    },
    "severity": {
      "type": "score",
      "score": 2.88,
      "confidence": 0.89,
      "probabilities": { "0": 0.0, "1": 0.02, "2": 0.08, "3": 0.9 },
      "legend": { "0": "No impact", "1": "Minor", "2": "Major", "3": "Critical" }
    }
  },
  "usage": { "input_tokens": 212, "output_tokens": 0 },
  "aireserve": { "request_id": "6b1d…", "model": "clef-flash" }
}
```

Every response carries an `aireserve` envelope with the request id to quote to support and the
model the decision billed under.

## Request

| Field | Type | Notes |
| - | - | - |
| `model` | enum | Required. `clef` (27B, 64K context, highest precision) or `clef-flash` (9B, 24K context, fastest and cheapest). |
| `state` | any | Required. The situation to decide on: a string, or structured JSON (records, chat logs, application state). Long text is truncated upstream to fit the context window. |
| `questions` | object | Required, 1–64 entries. Keys are your question ids (letters, digits, `_`, `.`, `-`; max 100 chars); answers come back under the same ids. |
| `images` | array | Optional, up to 4 embedded PNG / JPEG / WebP images placed before the state (4 MiB and 16 MP each). Remote URLs are not accepted. |

### Question types

| `type` | Ask | `criteria` | Answer |
| - | - | - | - |
| `noul` | A yes/no question. | — | `noul`: probability the answer is yes (0–1). |
| `choice` | Pick one of your options. | Object of `option id → description`. | `choice`, `confidence`, and `probabilities` over every option. |
| `score` | Rate against an ordered rubric. | Array of level descriptions, lowest first. | `score` (probability-weighted, 0 = lowest level), `confidence`, `probabilities`, `legend`. |

Every question takes `instructions` — the question itself, plus any policy the model should apply.
Questions are answered independently against the same state; the model cannot see one answer while
producing another, so put shared context in `state` or in each question's `instructions`.

> [!TIP]
>
> Decisions are **calibrated**: a `noul` of `0.6` means "more likely yes than no, but not by
> much", so threshold on the number rather than rounding it. Route the confident cases
> automatically and send the uncertain band to a person or a larger model.

## Use it as a gate

The common shape is a cheap decision in front of an expensive model: decide whether the turn
needs the large model, a tool call, or a human, and only then spend on it.

```python theme={"dark"}
import httpx, os
from openai import OpenAI

API_KEY = os.environ["AIRESERVE_API_KEY"]
client = OpenAI(base_url="https://api.aireserve.com/v1", api_key=API_KEY)

def decide(state, questions, model="clef-flash"):
    r = httpx.post(
        "https://api.aireserve.com/v1/decisions",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"model": model, "state": state, "questions": questions},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["answers"]

message = "my invoice from last month double charged me, can you fix it today?"

answers = decide(message, {
    "needs_human": {"type": "noul", "instructions": "Does this require a human agent (refunds, legal, account closure)?"},
    "intent": {"type": "choice", "instructions": "What does the customer want?",
               "criteria": {"refund": "Money back", "question": "Information only", "bug": "Something is broken"}},
})

if answers["needs_human"]["noul"] > 0.7:
    escalate(message, intent=answers["intent"]["choice"])
else:
    reply = client.chat.completions.create(
        model="gpt-5.5",
        messages=[{"role": "system", "content": f"Customer intent: {answers['intent']['choice']}."},
                  {"role": "user", "content": message}],
    )
```

## Billing

| Model | Size | Context | Billed |
| - | - | - | - |
| `clef` | 27B | 64K | \$0.24 per 1M input tokens |
| `clef-flash` | 9B | 24K | \$0.038 per 1M input tokens |

Rates match Cloudflare's published Workers AI list prices. Decisions have no output tokens, so a
request costs its input alone: the serialized `state` and `questions`, plus images, which are
tokenized at one token per 32×32 pixel block and capped at 1,024 tokens each. The wallet holds an
in-process estimate before the call and settles on the token count Cloudflare reports; a decision
that fails — at the provider, on a timeout, or because the surface is not configured — is never
charged. Current rates are always on the [pricing page](https://aireserve.com/pricing).

## Data handling

Request bodies are sent to Cloudflare, Inc. (United States; served from Cloudflare's global
network). Under Cloudflare's published Workers AI data-usage terms, inputs and outputs are
Customer Content that Cloudflare does not use to train models or improve its services, does not
make available to other customers, and stores only when paired with a Cloudflare storage product
— which this route does not use — so it carries **no data-retention consent gate**. Still, send
the minimum state the decision needs. Details on the
[data-handling page](https://privacy.aireserve.com/data-handling).

## Errors

| Status | Meaning |
| - | - |
| `400` | Malformed request — an unknown model, no questions, a bad question type, or Cloudflare's validation message relayed (for example an unsupported image or state over the context window). |
| `402` | Spend cap exceeded or insufficient wallet balance. |
| `403` | Not a client-scoped key, or model not on the key's allowlist. |
| `429` | Rate limit exceeded, here or upstream. Retry after the `Retry-After` header. |
| `503` | Decisions are not configured on this deployment, or the provider is unavailable. Retry. |
| `504` | The provider timed out. Retry. |


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