> ## Documentation Index
> Fetch the complete documentation index at: https://liquidai-ovenmitt-fix-models--decision-models-matrix-row.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Decision Models

> Purpose-built models for structured decisions: classification, routing, and scoring in a single call with zero generated tokens

Decision models are a new class of AI model purpose-built for structured decisions. Instead of generating text token by token, a decision model evaluates a situation and returns calibrated probabilities across a fixed set of outcomes in a single call with zero generated tokens.

Liquid's decision model evaluates text, images, or both. Use the same Noul, Choice, and Score questions to classify an image, inspect a part for defects, or make a decision from a screenshot.

## Primitives

Every question you ask a decision model uses one of three types:

* **Noul**: A yes/no question that returns a probability between 0 and 1. Think of it as a boolean on a sliding scale. "Is this message spam?" might return `0.92`, meaning a 0.92 probability that the answer is yes.

* **Choice**: A pick-one-from-many question that returns a probability distribution over named options. "Which department should handle this?" might return `{"billing": 0.65, "technical": 0.30, "account": 0.05}`.

* **Score**: A rate-on-a-scale question that returns a probability-weighted position on an ordered rubric. "How urgent is this?" with three levels might return a score of `1.85` (between "Medium" and "High"), with a probability distribution over each level.

Pick the type that matches the shape of the answer your code needs.

| If the answer is... | Use | Example |
| - | - | - |
| Pick one from a set of unordered categories | **Choice** | Which department handles this ticket? |
| Rate something along an ordered scale with defined levels | **Score** | How severe is this bug? |
| Yes or no, where the probability itself is useful | **Noul** | Does this message contain personal data? |

**Noul vs Score**: A Noul at 0.5 means maximum uncertainty between yes and no. It says nothing about degree or intensity. If you want to measure degree (skill level, frustration, severity), use a Score with defined levels. If you need a yes/no gate, use a Noul.

**When the answer could fit more than one type**, think about what your code does next. If it branches on a category, use a Choice. If it compares against a threshold on a continuum, use a Score. If it gates on a boolean, use a Noul.

## Setup

1. Go to [console.liquid.ai](https://console.liquid.ai). If you don't have an account yet, register and join an organization.
2. Navigate to **Dashboard > API Keys**.
3. Create a new key and copy it. Keys are prefixed with `liquid_`.

Set the key as an environment variable:

```bash theme={null}
export LIQUID_API_KEY="liquid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

Install the SDK and create a client:

<Tabs>
  <Tab title="Python">
    For text-only inputs:

    ```bash theme={null}
    pip install typesafe-sdk
    ```

    ```python theme={null}
    import os
    from typesafe_sdk import TypeSafeClient

    client = TypeSafeClient(
        api_key=os.environ["LIQUID_API_KEY"],
        base_url="https://api.liquid.ai",
    )
    ```

    For [image inputs](#image-inputs), the SDK does not support images yet, so the image examples use [`requests`](https://pypi.org/project/requests/):

    ```bash theme={null}
    pip install requests
    ```
  </Tab>

  <Tab title="TypeScript">
    For text-only inputs:

    ```bash theme={null}
    npm install @typesafe-ai/sdk
    ```

    ```typescript theme={null}
    import { TypeSafeClient } from "@typesafe-ai/sdk";

    const client = new TypeSafeClient({
      apiKey: process.env.LIQUID_API_KEY!,
      baseURL: "https://api.liquid.ai",
    });
    ```

    For [image inputs](#image-inputs), the SDK does not support images yet, so the image examples use `fetch` instead.
  </Tab>
</Tabs>

You can also use the following prompt to give your agent to enable it to use Liquid AI's decision models.

```text theme={null}
Load https://docs.liquid.ai/.well-known/skills/decision-model/skill.md, then inspect this project for generated-text calls that are really bounded decisions. Recommend d1 replacements for classification, routing, scoring, reranking, and yes/no gates.
```

## Your First Call

A single API call contains the following fields:

1. **Model**: which decision model to use.
2. **State**: the context the model should evaluate. This can be plain text (a customer message, an email, a log entry) or a JSON object with structured fields.
3. **Questions**: one or more typed questions, each with a name, a type, and instructions. Choice and Score questions also take criteria that define the options or levels. You can ask multiple questions in the same call, and the model evaluates them all at once.
4. **Images** (optional): images to evaluate alongside the state. Pass them in the top-level `images` array. See [Image Inputs](#image-inputs) for the request format and examples.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -s https://api.liquid.ai/decisions/v1/systemone \
      -H "Authorization: Bearer $LIQUID_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "d1",
        "state": "I have been waiting over three weeks for my order and nobody has responded to my emails. This is completely unacceptable.",
        "questions": {
          "is_complaint": {
            "type": "noul",
            "instructions": "Is this message a complaint from the customer?"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from typesafe_sdk import Noul

    result = client.system_one(
        model="d1",
        state="I have been waiting over three weeks for my order and nobody has responded to my emails. This is completely unacceptable.",
        questions={
            "is_complaint": Noul(
                instructions="Is this message a complaint from the customer?",
            ),
        },
    )
    print(result.answers["is_complaint"].noul)  # 0.999
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await client.systemOne({
      model: "d1",
      state: "I have been waiting over three weeks for my order and nobody has responded to my emails. This is completely unacceptable.",
      questions: {
        is_complaint: {
          type: "noul",
          instructions: "Is this message a complaint from the customer?",
        },
      },
    });
    console.log(result.answers.is_complaint.noul); // 0.999
    ```
  </Tab>
</Tabs>

**Response:**

```json theme={null}
{
  "model": "d1",
  "answers": {
    "is_complaint": {
      "type": "noul",
      "noul": 0.999
    }
  },
  "usage": {
    "input_tokens": 84,
    "output_tokens": 0
  }
}
```

**Reading the response:**

* **`answers.is_complaint.noul`**: The probability that the answer is "yes." Here, `0.999` means a 0.999 probability that this is a complaint.
* **`usage.output_tokens`**: Always `0`. Decision models do not generate tokens.
* **`usage.input_tokens`**: The total input tokens across all questions, including image tokens when images are provided. Each question is charged for its text and all supplied images.

The response contains one answer per question, keyed by the question name. A Noul answer is a single probability. Choice and Score answers also include a full probability distribution and a `confidence` value.

## Usage Examples

### Noul

A Noul question returns a single probability between 0 and 1. Your code receives a float that you can threshold to make a binary decision, use as a weight, or pass directly to downstream logic. Values near 0 or 1 express a clear answer; values near 0.5 express genuine uncertainty.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -s https://api.liquid.ai/decisions/v1/systemone \
      -H "Authorization: Bearer $LIQUID_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "d1",
        "state": "You'\''re an absolute idiot and I hope your company goes bankrupt. I'\''m going to find out where you work.",
        "questions": {
          "is_harmful": {
            "type": "noul",
            "instructions": "Does this user message contain harmful, threatening, or abusive content?"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from typesafe_sdk import Noul

    result = client.system_one(
        model="d1",
        state="You're an absolute idiot and I hope your company goes bankrupt. I'm going to find out where you work.",
        questions={
            "is_harmful": Noul(
                instructions="Does this user message contain harmful, threatening, or abusive content?",
            ),
        },
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await client.systemOne({
      model: "d1",
      state: "You're an absolute idiot and I hope your company goes bankrupt. I'm going to find out where you work.",
      questions: {
        is_harmful: {
          type: "noul",
          instructions: "Does this user message contain harmful, threatening, or abusive content?",
        },
      },
    });
    ```
  </Tab>
</Tabs>

**Response** (`answers` field):

```json theme={null}
{
  "is_harmful": {
    "type": "noul",
    "noul": 0.99
  }
}
```

**Using the result:**

```python theme={null}
p = result.answers["is_harmful"].noul

if p > 0.8:
    action = "block"
elif p < 0.2:
    action = "allow"
else:
    action = "human_review"
```

### Choice

A Choice question returns the selected option, a probability distribution over all options, and a `confidence` value. `confidence` summarizes how clear-cut the answer is: high when one option clearly wins, lower when the probability is spread across several options. The distribution tells you not just the top pick but how much probability mass sits on the runner-up, which is useful for flagging ambiguous cases or routing to a fallback.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -s https://api.liquid.ai/decisions/v1/systemone \
      -H "Authorization: Bearer $LIQUID_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "d1",
        "state": "Hi, I was charged twice for my subscription last month. The amounts are $29.99 on March 3rd and again on March 5th. Can you refund the duplicate charge?",
        "questions": {
          "intent": {
            "type": "choice",
            "instructions": "What is the primary topic of this customer inquiry?",
            "criteria": {
              "billing": "Questions about charges, invoices, refunds, or payment methods",
              "technical": "Bug reports, feature requests, or how-to questions about the product",
              "shipping": "Order status, delivery tracking, or shipping address changes",
              "returns": "Return requests, exchanges, or product condition issues",
              "account": "Login issues, profile updates, or subscription management"
            }
          }
        }
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from typesafe_sdk import Choice

    result = client.system_one(
        model="d1",
        state="Hi, I was charged twice for my subscription last month. The amounts are $29.99 on March 3rd and again on March 5th. Can you refund the duplicate charge?",
        questions={
            "intent": Choice(
                instructions="What is the primary topic of this customer inquiry?",
                criteria={
                    "billing": "Questions about charges, invoices, refunds, or payment methods",
                    "technical": "Bug reports, feature requests, or how-to questions about the product",
                    "shipping": "Order status, delivery tracking, or shipping address changes",
                    "returns": "Return requests, exchanges, or product condition issues",
                    "account": "Login issues, profile updates, or subscription management",
                },
            ),
        },
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await client.systemOne({
      model: "d1",
      state: "Hi, I was charged twice for my subscription last month. The amounts are $29.99 on March 3rd and again on March 5th. Can you refund the duplicate charge?",
      questions: {
        intent: {
          type: "choice",
          instructions: "What is the primary topic of this customer inquiry?",
          criteria: {
            billing: "Questions about charges, invoices, refunds, or payment methods",
            technical: "Bug reports, feature requests, or how-to questions about the product",
            shipping: "Order status, delivery tracking, or shipping address changes",
            returns: "Return requests, exchanges, or product condition issues",
            account: "Login issues, profile updates, or subscription management",
          },
        },
      },
    });
    ```
  </Tab>
</Tabs>

**Response** (`answers` field):

```json theme={null}
{
  "intent": {
    "type": "choice",
    "choice": "billing",
    "probabilities": {
      "billing": 0.9997,
      "account": 0.0002,
      "returns": 0.00005,
      "shipping": 0.00003,
      "technical": 0.00002
    },
    "confidence": 0.9996
  }
}
```

**Using the result:**

```python theme={null}
intent = result.answers["intent"].choice
confidence = result.answers["intent"].confidence

queue_map = {
    "billing": "billing-team",
    "technical": "engineering-support",
    "shipping": "logistics",
    "returns": "returns-desk",
    "account": "account-management",
}

target_queue = queue_map[intent]
print(f"Route to: {target_queue} (confidence: {confidence:.2f})")
# Route to: billing-team (confidence: 1.00)
```

### Score

A Score question returns a continuous value across an ordered rubric you define, plus the probability distribution over each level. The value is the probability-weighted position on the scale: if you define four levels (0 through 3), a score of `2.9995` means the model places nearly all weight on the top level.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -s https://api.liquid.ai/decisions/v1/systemone \
      -H "Authorization: Bearer $LIQUID_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "d1",
        "state": "Our production API is returning 500 errors on every request. All customers are affected. Revenue impact is approximately $12,000 per hour. Started 15 minutes ago.",
        "questions": {
          "urgency": {
            "type": "score",
            "instructions": "How urgent is this support request?",
            "criteria": [
              "Can wait: no immediate business impact, can be addressed in normal queue",
              "Should handle today: minor inconvenience or non-blocking issue",
              "Time-sensitive: noticeable customer impact, needs attention within hours",
              "Blocking revenue: critical system failure affecting customers or revenue"
            ]
          }
        }
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from typesafe_sdk import Score

    result = client.system_one(
        model="d1",
        state="Our production API is returning 500 errors on every request. All customers are affected. Revenue impact is approximately $12,000 per hour. Started 15 minutes ago.",
        questions={
            "urgency": Score(
                instructions="How urgent is this support request?",
                criteria=[
                    "Can wait: no immediate business impact, can be addressed in normal queue",
                    "Should handle today: minor inconvenience or non-blocking issue",
                    "Time-sensitive: noticeable customer impact, needs attention within hours",
                    "Blocking revenue: critical system failure affecting customers or revenue",
                ],
            ),
        },
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const result = await client.systemOne({
      model: "d1",
      state: "Our production API is returning 500 errors on every request. All customers are affected. Revenue impact is approximately $12,000 per hour. Started 15 minutes ago.",
      questions: {
        urgency: {
          type: "score",
          instructions: "How urgent is this support request?",
          criteria: [
            "Can wait: no immediate business impact, can be addressed in normal queue",
            "Should handle today: minor inconvenience or non-blocking issue",
            "Time-sensitive: noticeable customer impact, needs attention within hours",
            "Blocking revenue: critical system failure affecting customers or revenue",
          ],
        },
      },
    });
    ```
  </Tab>
</Tabs>

**Response** (`answers` field):

```json theme={null}
{
  "urgency": {
    "type": "score",
    "score": 2.9995,
    "confidence": 0.9995,
    "probabilities": {
      "0": 0.00001,
      "1": 0.00002,
      "2": 0.0004,
      "3": 0.9996
    },
    "legend": {
      "0": "Can wait: no immediate business impact, can be addressed in normal queue",
      "1": "Should handle today: minor inconvenience or non-blocking issue",
      "2": "Time-sensitive: noticeable customer impact, needs attention within hours",
      "3": "Blocking revenue: critical system failure affecting customers or revenue"
    }
  }
}
```

**Using the result:**

```python theme={null}
score = result.answers["urgency"].score

if score >= 2.5:
    print("ACTION: Page on-call engineer immediately")
elif score >= 1.5:
    print("ACTION: Escalate to senior support")
else:
    print("ACTION: Add to standard queue")
```

### Combining All Three Primitives

You can ask multiple questions of different types in the same call. The model evaluates all of them at once against the same state, so you get a complete decision in one round trip. This is useful when a single piece of input needs to be classified, routed, and prioritized together.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -s https://api.liquid.ai/decisions/v1/systemone \
      -H "Authorization: Bearer $LIQUID_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "d1",
        "state": "{\"message\": \"The checkout page crashes with a white screen whenever I try to apply a promo code. I'\''ve tried three different browsers. This is blocking a $4,200 order for our team and we need to place it before our procurement window closes on Friday.\", \"account\": {\"plan\": \"enterprise\", \"arr\": 52000, \"customer_since\": \"2022-03-15\"}}",
        "questions": {
          "is_bug": {
            "type": "noul",
            "instructions": "Is the customer reporting a software bug (as opposed to a usage question, feature request, or account issue)?"
          },
          "team": {
            "type": "choice",
            "instructions": "Which team should handle this ticket?",
            "criteria": {
              "billing": "Billing, invoicing, charges, and payment method issues",
              "engineering": "Software bugs, crashes, and technical malfunctions",
              "frontend": "UI/UX issues, display problems, and browser-specific bugs",
              "account": "Account setup, permissions, plan changes, and access issues"
            }
          },
          "urgency": {
            "type": "score",
            "instructions": "How urgent is this ticket? Consider business impact, time sensitivity, and customer tier.",
            "criteria": [
              "Low: no immediate impact, standard queue",
              "Medium: some business impact, handle within 24 hours",
              "High: significant business impact or time-sensitive, handle within 4 hours"
            ]
          }
        }
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import json
    from typesafe_sdk import Choice, Noul, Score

    ticket = {
        "message": "The checkout page crashes with a white screen whenever I try to apply a promo code. I've tried three different browsers. This is blocking a $4,200 order for our team and we need to place it before our procurement window closes on Friday.",
        "account": {
            "plan": "enterprise",
            "arr": 52000,
            "customer_since": "2022-03-15",
        },
    }

    result = client.system_one(
        model="d1",
        state=json.dumps(ticket),
        questions={
            "is_bug": Noul(
                instructions="Is the customer reporting a software bug (as opposed to a usage question, feature request, or account issue)?",
            ),
            "team": Choice(
                instructions="Which team should handle this ticket?",
                criteria={
                    "billing": "Billing, invoicing, charges, and payment method issues",
                    "engineering": "Software bugs, crashes, and technical malfunctions",
                    "frontend": "UI/UX issues, display problems, and browser-specific bugs",
                    "account": "Account setup, permissions, plan changes, and access issues",
                },
            ),
            "urgency": Score(
                instructions="How urgent is this ticket? Consider business impact, time sensitivity, and customer tier.",
                criteria=[
                    "Low: no immediate impact, standard queue",
                    "Medium: some business impact, handle within 24 hours",
                    "High: significant business impact or time-sensitive, handle within 4 hours",
                ],
            ),
        },
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    const ticket = {
      message: "The checkout page crashes with a white screen whenever I try to apply a promo code. I've tried three different browsers. This is blocking a $4,200 order for our team and we need to place it before our procurement window closes on Friday.",
      account: {
        plan: "enterprise",
        arr: 52000,
        customer_since: "2022-03-15",
      },
    };

    const result = await client.systemOne({
      model: "d1",
      state: JSON.stringify(ticket),
      questions: {
        is_bug: {
          type: "noul",
          instructions: "Is the customer reporting a software bug (as opposed to a usage question, feature request, or account issue)?",
        },
        team: {
          type: "choice",
          instructions: "Which team should handle this ticket?",
          criteria: {
            billing: "Billing, invoicing, charges, and payment method issues",
            engineering: "Software bugs, crashes, and technical malfunctions",
            frontend: "UI/UX issues, display problems, and browser-specific bugs",
            account: "Account setup, permissions, plan changes, and access issues",
          },
        },
        urgency: {
          type: "score",
          instructions: "How urgent is this ticket? Consider business impact, time sensitivity, and customer tier.",
          criteria: [
            "Low: no immediate impact, standard queue",
            "Medium: some business impact, handle within 24 hours",
            "High: significant business impact or time-sensitive, handle within 4 hours",
          ],
        },
      },
    });
    ```
  </Tab>
</Tabs>

**Response** (`answers` field):

```json theme={null}
{
  "is_bug": {
    "type": "noul",
    "noul": 0.9998
  },
  "team": {
    "type": "choice",
    "choice": "engineering",
    "probabilities": {
      "engineering": 0.80,
      "frontend": 0.18,
      "billing": 0.02,
      "account": 0.0005
    },
    "confidence": 0.74
  },
  "urgency": {
    "type": "score",
    "score": 1.996,
    "confidence": 0.995,
    "probabilities": {
      "0": 0.0002,
      "1": 0.004,
      "2": 0.996
    },
    "legend": {
      "0": "Low: no immediate impact, standard queue",
      "1": "Medium: some business impact, handle within 24 hours",
      "2": "High: significant business impact or time-sensitive, handle within 4 hours"
    }
  }
}
```

**Using the result:**

```python theme={null}
answers = result.answers

is_bug = answers["is_bug"].noul > 0.7
team = answers["team"].choice
team_confidence = answers["team"].confidence
urgency = answers["urgency"].score

if is_bug and urgency > 1.5:
    print(f"ESCALATE to {team} on-call (SLA: 4h)")
elif urgency > 1.0:
    print(f"PRIORITIZE in {team} queue (SLA: 24h)")
else:
    print(f"QUEUE in {team} standard backlog")

if team_confidence < 0.5:
    probs = answers["team"].probabilities
    runner_up = sorted(probs.items(), key=lambda x: x[1], reverse=True)[1]
    print(f"NOTE: Routing uncertain. Runner-up: {runner_up[0]} ({runner_up[1]:.0%})")

# ESCALATE to engineering on-call (SLA: 4h)
# The NOTE line only prints when team confidence is below 0.5.
```

## Image Inputs

Send images to the decision model through the same `/decisions/v1/systemone` endpoint used for text decisions. Add an `images` array alongside `model`, `state`, and `questions`. The question types and response format stay the same.

<Note>
  Vision is available through the Liquid API with the paid `d1` model. `d1:free` is text-only.
</Note>

Each image can be a Base64 data URL or an object with `content_type` and `base64` fields. Remote image URLs are not accepted. If an image is hosted online, download it and encode its contents before sending the request.

### Single Image Input

Pass a single image as a Base64 data URL in the `images` array. The model evaluates it alongside the text state.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    IMAGE_BASE64=$(base64 < image.jpg | tr -d '\r\n')

    curl -s https://api.liquid.ai/decisions/v1/systemone \
      -H "Authorization: Bearer $LIQUID_API_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @- <<JSON
    {
      "model": "d1",
      "state": "Camera image of a circuit board on the production line.",
      "images": ["data:image/jpeg;base64,$IMAGE_BASE64"],
      "questions": {
        "defect": {
          "type": "noul",
          "instructions": "Does this circuit board have a visible defect?"
        }
      }
    }
    JSON
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import base64
    import os
    from pathlib import Path

    import requests

    image = base64.b64encode(Path("image.jpg").read_bytes()).decode("ascii")

    response = requests.post(
        "https://api.liquid.ai/decisions/v1/systemone",
        headers={"Authorization": f"Bearer {os.environ['LIQUID_API_KEY']}"},
        json={
            "model": "d1",
            "state": "Camera image of a circuit board on the production line.",
            "images": [f"data:image/jpeg;base64,{image}"],
            "questions": {
                "defect": {
                    "type": "noul",
                    "instructions": "Does this circuit board have a visible defect?",
                }
            },
        },
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { readFileSync } from "node:fs";

    const image = readFileSync("image.jpg").toString("base64");

    const response = await fetch("https://api.liquid.ai/decisions/v1/systemone", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.LIQUID_API_KEY!}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "d1",
        state: "Camera image of a circuit board on the production line.",
        images: [`data:image/jpeg;base64,${image}`],
        questions: {
          defect: {
            type: "noul",
            instructions: "Does this circuit board have a visible defect?",
          },
        },
      }),
    });

    ```
  </Tab>
</Tabs>

**Response** (`answers` field):

```json theme={null}
{
  "defect": {
    "type": "noul",
    "noul": 0.85
  }
}
```

**Using the result:**

```python theme={null}
p = result["answers"]["defect"]["noul"]

if p > 0.8:
    action = "reject"
elif p < 0.2:
    action = "pass"
else:
    action = "manual_review"
```

The object form is equivalent to a data URL and accepts `content_type` and `base64` fields without the `data:` prefix:

```json theme={null}
{
  "images": [
    {
      "content_type": "image/jpeg",
      "base64": "<BASE64_ENCODED_IMAGE>"
    }
  ]
}
```

### Multi-Image Input

All questions in a request receive all images. The order of the images matters. Refer to images by position in the state or question instructions.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    REF_BASE64=$(base64 < image1.jpg | tr -d '\r\n')
    INSPECT_BASE64=$(base64 < image2.jpg | tr -d '\r\n')

    curl -s https://api.liquid.ai/decisions/v1/systemone \
      -H "Authorization: Bearer $LIQUID_API_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @- <<JSON
    {
      "model": "d1",
      "state": "The first image shows a reference circuit board with no defects. The second image shows the board being inspected.",
      "images": ["data:image/jpeg;base64,$REF_BASE64", "data:image/jpeg;base64,$INSPECT_BASE64"],
      "questions": {
        "defect": {
          "type": "noul",
          "instructions": "Does the board in the second image have a visible defect compared with the reference board in the first image?"
        }
      }
    }
    JSON
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import base64
    import os
    from pathlib import Path

    import requests

    image1 = base64.b64encode(Path("image1.jpg").read_bytes()).decode("ascii")
    image2 = base64.b64encode(Path("image2.jpg").read_bytes()).decode("ascii")

    response = requests.post(
        "https://api.liquid.ai/decisions/v1/systemone",
        headers={"Authorization": f"Bearer {os.environ['LIQUID_API_KEY']}"},
        json={
            "model": "d1",
            "state": "The first image shows a reference circuit board with no defects. The second image shows the board being inspected.",
            "images": [
                f"data:image/jpeg;base64,{image1}",
                f"data:image/jpeg;base64,{image2}",
            ],
            "questions": {
                "defect": {
                    "type": "noul",
                    "instructions": "Does the board in the second image have a visible defect compared with the reference board in the first image?",
                }
            },
        },
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { readFileSync } from "node:fs";

    const image1 = readFileSync("image1.jpg").toString("base64");
    const image2 = readFileSync("image2.jpg").toString("base64");

    const response = await fetch("https://api.liquid.ai/decisions/v1/systemone", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.LIQUID_API_KEY!}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        model: "d1",
        state: "The first image shows a reference circuit board with no defects. The second image shows the board being inspected.",
        images: [
          `data:image/jpeg;base64,${image1}`,
          `data:image/jpeg;base64,${image2}`,
        ],
        questions: {
          defect: {
            type: "noul",
            instructions: "Does the board in the second image have a visible defect compared with the reference board in the first image?",
          },
        },
      }),
    });

    ```
  </Tab>
</Tabs>

**Response** (`answers` field):

```json theme={null}
{
  "defect": {
    "type": "noul",
    "noul": 0.92
  }
}
```

### Image Requirements

| Requirement | Limit |
| - | - |
| Formats | JPEG (`image/jpeg`), PNG (`image/png`), WebP (`image/webp`), GIF (`image/gif`) |
| Images per request | Up to 8 |
| Request size | Keep the entire JSON body under 4.5 MB, including Base64 image data, state, and questions |
| Total image patches | Up to 10,000 patches of 32 × 32 pixels across all images in a request |
| Aspect ratio | The longer side of each image can be at most 100 times the shorter side |

Base64 encoding increases the request size compared with the original files. Resize or compress images before encoding them if the request is too large, and use the media type that matches each file.

<Note>
  If a request returns ``The model `d1:free` does not accept images.``, use `d1`. If the same error names `d1`, image input is not available for that model on the endpoint you called.
</Note>

### Image Token Usage

Each image is billed at 1.5 input tokens per 32 × 32 pixel patch, rounded up per image:

```text theme={null}
patches = ceil(width / 32) × ceil(height / 32)
image_tokens = ceil(patches × 1.5)
```

For example, a 1024 × 1024 image covers 1,024 patches and contributes 1,536 input tokens per question. Two questions about that image contribute 3,072 image tokens, plus the text tokens for each question.

Every question is charged for its text and all the images again. These tokens are included in `usage.input_tokens` and charged at the model's input token rate. Image tokens also count toward each question's input token limit. `usage.output_tokens` remains `0`.

## When to Use Decision Models

Decision models are a good fit when the answer is a structured decision: classification, categorization, routing (tickets, emails, requests), scoring, triage, content moderation, guardrails and safety checks, LLM-as-judge replacement, agent tool-call approval, and model routing or cascades.

With image input, the same primitives support visual inspection, image classification, and decisions based on screenshots.

Use a language model instead for free-form text generation, creative writing, multi-turn conversation, complex multi-step reasoning, open-ended Q\&A, summarization, and code generation.

To move existing LLM calls to a decision model, see the [Decision Model Guide](/guides/decision-model-guide).

## Next Steps

* [Decision Model Guide](/guides/decision-model-guide) for migrating LLM classification, routing, and scoring calls to d1
* [Model Library](/lfm/models/complete-library) for all available Liquid AI models


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