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

# Decisions

> Jev (TypeSafe)-compatible endpoint: answer typed choice/noul/score questions against a shared state object.

## Overview

The `/v1/scaledown` endpoint mirrors [TypeSafe's Jev Decisions API](https://openrouter.ai/docs/guides/community/jev) request/response shape. You send a `state` object plus a `questions` map, and get back one typed `answer` per question. `choice` and `noul` questions are answered using the same calibrated scoring [`/classify`](/api-reference/classify) uses; `score` questions are not supported - see [`score` behavior](#score-behavior) below.

## Request

<ParamField body="model" type="string" default="classify-1">
  Optional. The only supported value is `"classify-1"`, which is also the default when omitted. Any other value is rejected with `422`.
</ParamField>

<ParamField body="state" type="object" required>
  The item being decided on.

  <Expandable title="State fields">
    <ParamField body="text" type="string">
      The text to evaluate every question against. Provide `text`, `document`, or both.
    </ParamField>

    <ParamField body="document" type="string">
      A base64-encoded file to evaluate. Supported formats: JPEG, PNG, TIFF, single-page PDF, multi-page PDF. Non-standard extension - not part of the Jev API.
    </ParamField>

    <ParamField body="document_mime_type" type="string">
      MIME type of `document` (e.g. `"image/jpeg"`, `"application/pdf"`). Required when `document` is provided.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="questions" type="object" required>
  A map of question name → question definition. Must contain at least one entry. Every question is answered against the same `state`, concurrently.

  <Expandable title="choice question">
    <ParamField body="type" type="string" required>
      `"choice"` - pick exactly one option from `criteria`.
    </ParamField>

    <ParamField body="instructions" type="string">
      Optional guidance for how to choose (e.g. "Which single category best describes the post?").
    </ParamField>

    <ParamField body="criteria" type="object" required>
      Map of option key → description, e.g. `{ "billing": "About a charge, invoice, or refund." }`. At least one entry required.
    </ParamField>
  </Expandable>

  <Expandable title="noul question">
    <ParamField body="type" type="string" required>
      `"noul"` - an independent yes/no question, answered as a probability.
    </ParamField>

    <ParamField body="instructions" type="string">
      The yes/no question to evaluate, e.g. `"Is the sentiment positive?"`.
    </ParamField>
  </Expandable>

  <Expandable title="score question (unsupported)">
    <ParamField body="type" type="string" required>
      `"score"` - accepted for request-shape compatibility only, never actually evaluated. See [`score` behavior](#score-behavior).
    </ParamField>
  </Expandable>
</ParamField>

## Response

<ResponseField name="model" type="string">
  Always `"classify-1"`.
</ResponseField>

<ResponseField name="answers" type="object">
  Map of question name → typed answer, matching the `questions` keys from the request.

  <Expandable title="choice answer">
    <ResponseField name="type" type="string">
      `"choice"`
    </ResponseField>

    <ResponseField name="choice" type="string">
      The chosen option key.
    </ResponseField>

    <ResponseField name="probabilities" type="object">
      Map of option key → probability. Sums to `1.0`.
    </ResponseField>

    <ResponseField name="confidence" type="number">
      The chosen option's probability (same value as `probabilities[choice]`).
    </ResponseField>
  </Expandable>

  <Expandable title="noul answer">
    <ResponseField name="type" type="string">
      `"noul"`
    </ResponseField>

    <ResponseField name="noul" type="number">
      P(yes) - independent probability, 0 to 1.
    </ResponseField>
  </Expandable>

  <Expandable title="unsupported answer">
    <ResponseField name="type" type="string">
      `"unsupported"`
    </ResponseField>

    <ResponseField name="reason" type="string">
      Why this question type isn't answered - always `"'score' questions are not supported by this API"` today. Only appears in a **mixed** request that also has at least one `choice`/`noul` question - see [`score` behavior](#score-behavior).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="usage" type="object">
  Token usage and cost, summed across every internal call the request fanned out to (one per `choice`/`noul` question).

  <Expandable title="Usage fields">
    <ResponseField name="input_tokens" type="integer">
      Sum of input tokens across every question answered.
    </ResponseField>

    <ResponseField name="output_tokens" type="integer">
      Sum of output tokens across every question answered.
    </ResponseField>

    <ResponseField name="cost" type="number">
      Total cost in USD for the request.
    </ResponseField>
  </Expandable>
</ResponseField>

## `score` behavior

We have no ordered-scale scoring primitive, so a `score` question is never actually evaluated. What happens depends on whether the request has anything else in it:

* **Mixed request** (at least one `choice`/`noul` question alongside the `score` question(s)): returns `200`. The `choice`/`noul` questions are answered normally; each `score` question's answer comes back as `{"type": "unsupported", "reason": "..."}` and contributes nothing to `usage`.
* **All-`score` request** (every question in `questions` is type `score`): returns `422`. Nothing in the request could be answered, so it fails outright instead of returning a `200` full of `"unsupported"` placeholders.

## Error responses

| Status                     | Meaning                                                                                                                                                                                                                                 |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `422 Unprocessable Entity` | Malformed request body, empty `questions` map, empty `criteria` on a `choice` question, neither `state.text` nor `state.document` provided, every question in the request is type `score`, an unsupported `model` value, or OCR failed. |
| `402 Payment Required`     | Insufficient credits.                                                                                                                                                                                                                   |
| `502 Bad Gateway`          | Model service unavailable or returned an error.                                                                                                                                                                                         |
| `504 Gateway Timeout`      | Request timed out.                                                                                                                                                                                                                      |

## Authentication

Include your API key in every request using the `x-api-key` header.

```bash theme={null}
-H "x-api-key: <your-api-key>"
```

## Examples

### Single choice question

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.scaledown.xyz/v1/scaledown \
    -H "Content-Type: application/json" \
    -H "x-api-key: <your-api-key>" \
    -d '{
      "model": "classify-1",
      "state": { "text": "I was charged twice for my subscription this month." },
      "questions": {
        "category": {
          "type": "choice",
          "instructions": "Which single category best describes the post?",
          "criteria": {
            "billing": "About a charge, invoice, refund, or payment problem.",
            "technical": "About a bug or something not working.",
            "account": "About login, access, or account settings."
          }
        }
      }
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.scaledown.xyz/v1/scaledown",
      headers={"x-api-key": "<your-api-key>"},
      json={
          "model": "classify-1",
          "state": {"text": "I was charged twice for my subscription this month."},
          "questions": {
              "category": {
                  "type": "choice",
                  "instructions": "Which single category best describes the post?",
                  "criteria": {
                      "billing": "About a charge, invoice, refund, or payment problem.",
                      "technical": "About a bug or something not working.",
                      "account": "About login, access, or account settings.",
                  },
              }
          },
      },
  )
  print(response.json())
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.scaledown.xyz/v1/scaledown", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "<your-api-key>",
    },
    body: JSON.stringify({
      model: "classify-1",
      state: { text: "I was charged twice for my subscription this month." },
      questions: {
        category: {
          type: "choice",
          instructions: "Which single category best describes the post?",
          criteria: {
            billing: "About a charge, invoice, refund, or payment problem.",
            technical: "About a bug or something not working.",
            account: "About login, access, or account settings.",
          },
        },
      },
    }),
  });
  const data = await response.json();
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "model": "classify-1",
  "answers": {
    "category": {
      "type": "choice",
      "choice": "billing",
      "probabilities": { "billing": 0.93, "technical": 0.04, "account": 0.03 },
      "confidence": 0.93
    }
  },
  "usage": { "input_tokens": 62, "output_tokens": 1, "cost": 0.0000026 }
}
```

***

### Mixed choice + noul questions

`choice` and `noul` questions can be combined in one request. Both are answered concurrently against the same `state`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.scaledown.xyz/v1/scaledown \
    -H "Content-Type: application/json" \
    -H "x-api-key: <your-api-key>" \
    -d '{
      "state": { "text": "The invoice is overdue and the customer is threatening to cancel." },
      "questions": {
        "category": {
          "type": "choice",
          "criteria": {
            "billing": "About a charge, invoice, or payment matter.",
            "legal": "About a legal or contractual dispute."
          }
        },
        "is_churn_risk": {
          "type": "noul",
          "instructions": "Does this text signal the customer may cancel or leave?"
        }
      }
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.scaledown.xyz/v1/scaledown",
      headers={"x-api-key": "<your-api-key>"},
      json={
          "state": {"text": "The invoice is overdue and the customer is threatening to cancel."},
          "questions": {
              "category": {
                  "type": "choice",
                  "criteria": {
                      "billing": "About a charge, invoice, or payment matter.",
                      "legal": "About a legal or contractual dispute.",
                  },
              },
              "is_churn_risk": {
                  "type": "noul",
                  "instructions": "Does this text signal the customer may cancel or leave?",
              },
          },
      },
  )
  print(response.json())
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.scaledown.xyz/v1/scaledown", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "<your-api-key>",
    },
    body: JSON.stringify({
      state: { text: "The invoice is overdue and the customer is threatening to cancel." },
      questions: {
        category: {
          type: "choice",
          criteria: {
            billing: "About a charge, invoice, or payment matter.",
            legal: "About a legal or contractual dispute.",
          },
        },
        is_churn_risk: {
          type: "noul",
          instructions: "Does this text signal the customer may cancel or leave?",
        },
      },
    }),
  });
  const data = await response.json();
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "model": "classify-1",
  "answers": {
    "category": {
      "type": "choice",
      "choice": "billing",
      "probabilities": { "billing": 0.88, "legal": 0.12 },
      "confidence": 0.88
    },
    "is_churn_risk": { "type": "noul", "noul": 0.79 }
  },
  "usage": { "input_tokens": 94, "output_tokens": 2, "cost": 0.0000039 }
}
```

***

### A `score` question in the mix

`score` questions are accepted but always answered as `"unsupported"` - the rest of the request still succeeds.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.scaledown.xyz/v1/scaledown \
    -H "Content-Type: application/json" \
    -H "x-api-key: <your-api-key>" \
    -d '{
      "state": { "text": "Great product, but the onboarding was confusing." },
      "questions": {
        "sentiment": {
          "type": "choice",
          "criteria": { "positive": "Overall positive tone.", "negative": "Overall negative tone." }
        },
        "quality_score": {
          "type": "score",
          "instructions": "Rate overall quality from 1 to 5."
        }
      }
    }'
  ```
</CodeGroup>

**Response:** `sentiment` is answered normally; `quality_score` comes back as `unsupported` and costs nothing.

```json theme={null}
{
  "model": "classify-1",
  "answers": {
    "sentiment": {
      "type": "choice",
      "choice": "positive",
      "probabilities": { "positive": 0.81, "negative": 0.19 },
      "confidence": 0.81
    },
    "quality_score": {
      "type": "unsupported",
      "reason": "'score' questions are not supported by this API"
    }
  },
  "usage": { "input_tokens": 41, "output_tokens": 1, "cost": 0.0000017 }
}
```

***

### An all-`score` request

When **every** question in the request is `score`, nothing can be answered, so the request fails with `422` instead of returning `200` with everything marked unsupported.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.scaledown.xyz/v1/scaledown \
    -H "Content-Type: application/json" \
    -H "x-api-key: <your-api-key>" \
    -d '{
      "state": { "text": "Great product, but the onboarding was confusing." },
      "questions": {
        "quality_score": {
          "type": "score",
          "instructions": "Rate overall quality from 1 to 5."
        }
      }
    }'
  ```
</CodeGroup>

**Response:** `422 Unprocessable Entity`

```json theme={null}
{
  "detail": "'score' questions are not supported by this API, and no other question type was provided to answer."
}
```

## Notes

* `"classify-1"` is the only supported `model`. Omit it (defaults to `"classify-1"`) or pass it explicitly - any other value is rejected with `422`.
* Every `choice`/`noul` question in a request is one separate calibrated model call, run concurrently. `usage` is the sum across all of them - a request with a `choice` and two `noul` questions makes 3 calls and bills for all 3.
* A request made entirely of `score` questions returns `422`, not `200` - see [`score` behavior](#score-behavior).
* No `reasoning` field exists on this endpoint - it never generates a free-form explanation, unlike `/classify` with `reasoning: true`.
* No batching - each request evaluates one `state`. To classify many items, use [`/classify`](/api-reference/classify)'s `chunks` array instead.
* See [Differences from Jev](/api-reference/decisions-overview#differences-from-jev) for the full compatibility matrix.


## OpenAPI

````yaml POST /v1/scaledown
openapi: 3.1.0
info:
  title: ScaleDown API
  version: 1.0.0
servers:
  - url: https://api.scaledown.xyz
security:
  - apiKey: []
paths:
  /v1/scaledown:
    post:
      summary: Decisions
      description: >-
        Jev (TypeSafe)-compatible endpoint: answer typed choice/noul/score
        questions about a shared state object.
      operationId: decisions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - state
                - questions
              properties:
                model:
                  type: string
                  enum:
                    - classify-1
                  default: classify-1
                  description: >-
                    Optional. "classify-1" is the only supported value and also
                    the default when omitted. Any other value returns 422.
                state:
                  type: object
                  description: The item being decided on. Provide text, document, or both.
                  properties:
                    text:
                      type: string
                      description: The text to evaluate every question against.
                    document:
                      type: string
                      description: >-
                        A base64-encoded file to evaluate (image or PDF).
                        Non-standard extension, not part of the Jev API.
                    document_mime_type:
                      type: string
                      description: >-
                        MIME type of document. Required when document is
                        provided.
                questions:
                  type: object
                  description: >-
                    Map of question name to question definition. Must contain at
                    least one entry.
                  additionalProperties:
                    type: object
                    required:
                      - type
                    properties:
                      type:
                        type: string
                        enum:
                          - choice
                          - noul
                          - score
                        description: >-
                          choice: pick one option from criteria. noul:
                          independent yes/no question. score: never evaluated —
                          answered as unsupported if the request also has a
                          choice/noul question, or causes the whole request to
                          fail with 422 if every question is score.
                      instructions:
                        type: string
                        description: Optional guidance for how to answer the question.
                      criteria:
                        type: object
                        description: >-
                          Required for choice questions: map of option key to
                          description. At least one entry required.
                        additionalProperties:
                          type: string
      responses:
        '200':
          description: Successful decision
          content:
            application/json:
              schema:
                type: object
                properties:
                  model:
                    type: string
                    description: Always "classify-1".
                  answers:
                    type: object
                    description: >-
                      Map of question name to typed answer, matching the
                      questions keys from the request.
                    additionalProperties:
                      type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - choice
                            - noul
                            - unsupported
                        choice:
                          type: string
                          description: 'choice answers only: the chosen option key.'
                        probabilities:
                          type: object
                          description: >-
                            choice answers only: map of option key to
                            probability. Sums to 1.0.
                          additionalProperties:
                            type: number
                        confidence:
                          type: number
                          description: >-
                            choice answers only: the chosen option's
                            probability.
                        noul:
                          type: number
                          description: 'noul answers only: P(yes), 0 to 1.'
                        reason:
                          type: string
                          description: >-
                            unsupported answers only: why this question type
                            isn't answered.
                  usage:
                    type: object
                    description: >-
                      Token usage and cost, summed across every internal call
                      the request fanned out to.
                    properties:
                      input_tokens:
                        type: integer
                      output_tokens:
                        type: integer
                      cost:
                        type: number
        '402':
          description: Insufficient credits.
        '422':
          description: >-
            Malformed request body, empty questions map, empty criteria on a
            choice question, neither state.text nor state.document provided,
            every question in the request is type score, an unsupported model
            value, or OCR failed.
        '502':
          description: Model service unavailable or returned an error.
        '504':
          description: Request timed out.
components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key

````