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

# Create decision

> Get typed answers to named questions about a state

<Note>
**Preview.** The `/alpha` path and the request and response formats may change before this API is marked stable. See [release stages](https://docs.inworld.ai/portal/support.md#what-do-experimental-preview-and-stable-mean).
</Note>

Send a `state` and a map of typed questions to the selected decision model. It returns one answer per question: a yes/no probability (`noul`), a pick from your options (`choice`), or a rating on your levels (`score`). Answers are never free text, so your code can branch on them directly.

Choose an API model ID from the [model catalog](https://inworld.ai/models). The [Decisions guide](https://docs.inworld.ai/router/decisions.md) explains how to choose a model, run examples, and use the answers in your application. The reference examples use `typesafe/jev-latest`, a text-only model.

## Errors

Request validation returns `400` with `error.type: "invalid_request_error"` before sending the request to a model. For question validation, `error.param` names the field to fix. Other errors can omit `param`.

For example, a request to an available model with `state` present and `"questions": {"q": {"type": "rank"}}` returns:

```json
{
  "error": {
    "message": "questions.q.type: unknown question type \"rank\"; expected noul, choice or score",
    "type": "invalid_request_error",
    "param": "questions.q.type"
  }
}
```

Model errors relayed to your application keep their HTTP status and use `{"error": {"message": "...", "type": "..."}}`. Input that passes request validation can still be rejected by the model, including with `422`. A relayed `429` uses `rate_limit_error`; relayed `5xx` errors use `api_error`, except `504`, which uses `timeout_error`. These rate-limit and server errors have generic messages. Retry transient errors with exponential backoff and honor `Retry-After` when present.

Check the HTTP status and content type before parsing: authentication, account, and API-key rate-limit errors can use a different body. See [Errors in the Decisions guide](https://docs.inworld.ai/router/decisions.md#errors) for status codes and next steps.

## Image input

Use the [List models API](https://docs.inworld.ai/api-reference/modelsAPI/modelservice/list-models.md) with `output_modalities=decisions` to find decision models. In the response, check `models[].spec.inputModalities`. Choose a model whose `spec.inputModalities` includes `image`. Sending an image to a text-only model returns `400`.

Put image parts directly in the `state` array alongside text:

```json
{
  "state": [
    "Evaluate this screenshot.",
    {
      "type": "image_url",
      "image_url": {
        "url": "data:image/png;base64,<BASE64_IMAGE>",
        "detail": "auto"
      }
    }
  ]
}
```

This fragment illustrates `state`; a complete request also requires `model` and `questions`.

| Field or constraint | Accepted values and behavior |
|:--|:--|
| `image_url.url` | Inline PNG, JPEG or WebP data URL with standard base64 encoding: `data:image/png;base64,...`, `data:image/jpeg;base64,...` or `data:image/webp;base64,...`. Remote HTTP(S) URLs are rejected. |
| `image_url.detail` | Optional: `auto`, `low` or `high`. Some models ignore it. |
| Placement | Image parts must be direct elements of the `state` array. Nested image parts are treated as data, not image input. A top-level `images` field is rejected with `400`. |
| Other modalities | Audio and video input are not supported. |

Image-count and request-size limits depend on the selected model. The text-only example model's limits do not apply to all image requests. See [Evaluate an image](https://docs.inworld.ai/router/decisions.md#evaluate-an-image) for a complete Python request using a checkout screenshot.

## API reference

**Endpoint:** `POST https://api.inworld.ai/alpha/decisions`

### Authorization

- `Authorization` (string; required) — Your [authentication](../../../api-reference/introduction) credentials. For Basic authentication, please populate `Basic $INWORLD_API_KEY`.
  
  Please make sure your API Key has [write permissions for the Router API](https://docs.inworld.ai/api-reference/introduction.md#getting-an-api-key) in order to create, update, and delete routers. You can create a key in one command with the [Inworld CLI](../../../developer-tools/inworld-cli): `inworld workspace add-key`.

### Request body

Content type: `application/json`

- `model` (string; required) — API model ID selected from the Decisions catalog, for example `typesafe/jev-latest`.
- `state` (oneOf; required) — The content to evaluate: a string for text, or an object or array for structured data. Image-capable decision models also accept direct `image_url` parts in the `state` array, using inline base64 PNG, JPEG or WebP data URLs. Remote URLs are rejected; nested image parts are treated as data, not image input. Audio and video are not supported. See the [image input contract](https://docs.inworld.ai/api-reference/routerAPI/create-decision.md#image-input) for the part format, optional detail and model requirements.
- `questions` (object; required) — The questions to answer, keyed by ids you choose. Each answer comes back under the same id. The ids are not sent to the model and do not affect inference.

#### Request example

```json
{
  "model": "typesafe/jev-latest",
  "state": "Help! My payouts have been failing for 3 days.",
  "questions": {
    "is_urgent": {
      "type": "noul",
      "instructions": "Does this convey urgency?",
      "criteria": {
        "true": "Explicitly time-sensitive",
        "false": "No urgency expressed"
      }
    },
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this?",
      "criteria": {
        "billing": "Payments, invoicing, refunds",
        "technical": "Bugs, outages, integrations",
        "sales": "Pricing, upgrades, new accounts"
      }
    },
    "frustration": {
      "type": "score",
      "instructions": "How frustrated is the customer?",
      "criteria": [
        "Calm",
        "Frustrated",
        "Very angry"
      ]
    }
  }
}
```

### Response

Status: `200`. Content type: `application/json`.

- `model` (string) — The provider-qualified model that answered: a specific version (for example `typesafe/jev-1.13.0`), or the model family (for example `typesafe/jev`) when no version is reported.
- `answers` (object) — One answer per question, keyed by the ids used in `questions`.
- `usage` (object) — Token usage. Decisions are billed on `input_tokens` only; output tokens are not billed.
  - `input_tokens` (integer)
  - `output_tokens` (integer)
- `metadata` (object) — Inworld routing metadata, with the same keys as on chat completions.
  - `attempts` (object[])
    - `model` (string)
    - `status_code` (integer)
    - `duration_ms` (number)
    - `success` (boolean)
  - `generation_id` (string) — Unique identifier for this request.
  - `total_duration_ms` (integer) — Total request duration in milliseconds.

### Response examples

#### 200: One question of each type

```json
{
  "model": "typesafe/jev-1.13.0",
  "answers": {
    "is_urgent": {
      "type": "noul",
      "noul": 0.95
    },
    "department": {
      "type": "choice",
      "choice": "billing",
      "probabilities": {
        "billing": 0.88,
        "technical": 0.12,
        "sales": 0
      },
      "confidence": 0.81
    },
    "frustration": {
      "type": "score",
      "score": 1.05,
      "legend": {
        "0": "Calm",
        "1": "Frustrated",
        "2": "Very angry"
      },
      "probabilities": {
        "0": 0,
        "1": 0.95,
        "2": 0.05
      },
      "confidence": 0.92
    }
  },
  "usage": {
    "input_tokens": 402,
    "output_tokens": 69
  },
  "metadata": {
    "attempts": [
      {
        "model": "typesafe/jev-1.13.0",
        "status_code": 200,
        "duration_ms": 212.4,
        "success": true
      }
    ],
    "generation_id": "0f5d3c4e-8f0b-4a53-9a55-2f3a6f0d8a1b",
    "total_duration_ms": 212
  }
}
```

#### 400: default_response

```json
{
  "error": {
    "message": "questions.q.type: unknown question type \"rank\"; expected noul, choice or score",
    "type": "invalid_request_error",
    "param": "questions.q.type"
  }
}
```

#### 401: default_response

```json
"Unauthorized"
```

#### 413: default_response

```json
{
  "error": {
    "message": "request body exceeds the 10485760 bytes System One accepts",
    "type": "invalid_request_error"
  }
}
```

#### 422: default_response

```json
{
  "error": {
    "message": "'model' field is required",
    "type": "invalid_request_error",
    "code": "string",
    "param": "string"
  }
}
```

#### 502: default_response

```json
{
  "error": {
    "message": "'model' field is required",
    "type": "invalid_request_error",
    "code": "string",
    "param": "string"
  }
}
```

#### 503: default_response

```json
{
  "error": {
    "message": "too many concurrent System One requests; retry shortly",
    "type": "api_error"
  }
}
```

#### 504: default_response

```json
{
  "error": {
    "message": "System One upstream timed out",
    "type": "timeout_error"
  }
}
```

#### 529: default_response

```json
{
  "error": {
    "message": "'model' field is required",
    "type": "invalid_request_error",
    "code": "string",
    "param": "string"
  }
}
```

### Code examples

#### cURL

```bash
curl -X POST 'https://api.inworld.ai/alpha/decisions' \
  -H "Authorization: Basic $INWORLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "typesafe/jev-latest",
    "state": "Help! My payouts have been failing for 3 days.",
    "questions": {
      "is_urgent": {
        "type": "noul",
        "instructions": "Does this convey urgency?"
      },
      "department": {
        "type": "choice",
        "instructions": "Which team should handle this?",
        "criteria": {
          "billing": "Payments, invoicing, refunds",
          "technical": "Bugs, outages, integrations",
          "sales": "Pricing, upgrades, new accounts"
        }
      }
    }
  }'
```

#### Python

```python
import os
import requests

response = requests.post(
    "https://api.inworld.ai/alpha/decisions",
    headers={"Authorization": f"Basic {os.environ['INWORLD_API_KEY']}"},
    json={
        "model": "typesafe/jev-latest",
        "state": "Help! My payouts have been failing for 3 days.",
        "questions": {
            "is_urgent": {"type": "noul", "instructions": "Does this convey urgency?"},
            "department": {
                "type": "choice",
                "instructions": "Which team should handle this?",
                "criteria": {
                    "billing": "Payments, invoicing, refunds",
                    "technical": "Bugs, outages, integrations",
                    "sales": "Pricing, upgrades, new accounts",
                },
            },
        },
    },
    timeout=60,
)
response.raise_for_status()
answers = response.json()["answers"]
print(answers["is_urgent"]["noul"], answers["department"]["choice"])
```

#### JavaScript

```javascript
const response = await fetch('https://api.inworld.ai/alpha/decisions', {
  method: 'POST',
  headers: {
    Authorization: `Basic ${process.env.INWORLD_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'typesafe/jev-latest',
    state: 'Help! My payouts have been failing for 3 days.',
    questions: {
      is_urgent: { type: 'noul', instructions: 'Does this convey urgency?' },
      department: {
        type: 'choice',
        instructions: 'Which team should handle this?',
        criteria: {
          billing: 'Payments, invoicing, refunds',
          technical: 'Bugs, outages, integrations',
          sales: 'Pricing, upgrades, new accounts',
        },
      },
    },
  }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const { answers } = await response.json();
console.log(answers.is_urgent.noul, answers.department.choice);
```
