---
title: Decisions
---

# Decisions

`POST /v1/decisions`

Ask a decision model a set of typed questions about one shared input. The model returns a probability for every answer instead of generated text. This endpoint uses the OpenAI decisions request shape.

<Callout type="info">
  Every decision model can be called here or through [`/v1/systemone`](/docs/api-reference/systemone), whichever shape your code already speaks. Decision models are not available on the chat endpoints.
</Callout>

## Endpoint

```http
POST https://api.crossmodel.ai/v1/decisions
Authorization: Bearer cm-YOUR_KEY
Content-Type: application/json
```

## Request

```json
{
  "model": "typesafe/jev",
  "input": "Help! My payouts have been failing for 3 days.",
  "questions": [
    { "type": "predicate", "name": "urgent", "instructions": "Does this message convey urgency?" },
    {
      "type": "choice",
      "name": "team",
      "instructions": "Which team should handle this?",
      "choices": [{ "value": "billing" }, { "value": "technical" }, { "value": "sales" }]
    },
    {
      "type": "score",
      "name": "frustration",
      "instructions": "How frustrated is the customer?",
      "levels": [
        { "label": "calm", "description": "No sign of frustration" },
        { "label": "annoyed", "description": "Clearly unhappy" },
        { "label": "angry", "description": "Threatening to leave or complain" }
      ]
    }
  ]
}
```

| Parameter | Type | Required | Notes |
|------|------|------|------|
| `model` | string | Yes | A decision model ID, e.g. `typesafe/jev`. List them with `GET /v1/models?kind=decision`. |
| `input` | string or array | Yes | The content to decide about. A string, or an array of user messages (see [Input](#input)). |
| `questions` | array | Yes | One or more questions. See [Question types](#question-types). |
| `safety_identifier` | string | No | A stable ID for your end user. Forwarded to OpenAI models only; other models ignore it. |

Any other top-level field is rejected with `400 unknown_parameter`. There is no `stream`, `temperature` or `max_tokens`: a decision is one complete response.

### Input

A string is the simplest form. To send images, or several pieces of content, use an array of messages. Every message has role `user`.

```json
{
  "input": [
    {
      "role": "user",
      "content": [
        { "type": "input_text", "text": "Is this receipt legible?" },
        { "type": "input_image", "image_url": "data:image/png;base64,..." }
      ]
    }
  ]
}
```

Images are accepted only by models whose input modalities include `image`. Sending one to a text-only model returns `400 image_input_not_supported`.

### Question types

| `type` | Extra fields | Answer |
|------|------|------|
| `predicate` | none | `probability` that the answer is yes. |
| `choice` | `choices`: array of `{ "value", "description"? }`. `value` is a string or a boolean. | The chosen `choice`, a `confidence`, and a probability per option. |
| `score` | `levels`: array of `{ "label"?, "description"? }`, lowest first. | A `score`: the expected level index, from 0 (lowest level) to the number of levels minus 1 (highest). Also a `confidence` and a probability per level. |

Every question takes `instructions` (string, required) and `name` (string, optional). Names must be unique within a request.

## Response

```json
{
  "model": "typesafe/jev",
  "answers": [
    { "type": "predicate", "name": "urgent", "probability": 0.97 },
    {
      "type": "choice",
      "name": "team",
      "choice": "billing",
      "confidence": 0.91,
      "probabilities": [
        { "value": "billing", "probability": 0.93 },
        { "value": "technical", "probability": 0.06 },
        { "value": "sales", "probability": 0.01 }
      ]
    },
    {
      "type": "score",
      "name": "frustration",
      "score": 1.42,
      "confidence": 0.64,
      "probabilities": [
        { "value": 0, "label": "calm", "probability": 0.03 },
        { "value": 1, "label": "annoyed", "probability": 0.52 },
        { "value": 2, "label": "angry", "probability": 0.45 }
      ]
    }
  ],
  "usage": { "input_tokens": 148, "output_tokens": 0, "total_tokens": 148 }
}
```

Answers come back in the same order as the questions. `name` is `null` for a question that had no name.

A model may decline a single question. That answer has `"type": "refusal"` and an optional `reason`; the other answers are unaffected and the request is billed normally.

## Billing

Decision models are billed on input tokens only. The whole request counts: the input, every question's instructions, and every option or level description. There is no output price.

## Errors

Errors use the [OpenAI-compatible error format](/docs/errors).

| Status | `code` | Meaning |
|------|------|------|
| `400` | `unknown_parameter` | The body has a field this endpoint does not define. |
| `400` | `invalid_question_type` | `type` is not `predicate`, `choice` or `score`. |
| `400` | `empty_questions`, `duplicate_question_name`, `duplicate_choice_value` | The question set is empty or ambiguous. |
| `400` | `invalid_input`, `invalid_choice_value` | `input` or a choice value has the wrong shape. |
| `400` | `image_input_not_supported` | The model takes text only. |
| `400` | `model_not_supported_on_endpoint` | The model is a chat model. Use a chat endpoint. |
| `502` | `upstream_invalid_response` | The model returned an incomplete answer. You are not charged. |
