---
title: "Making decisions from JSON data | Nutrient Java SDK"
canonical_url: "https://www.nutrient.io/guides/java/extraction/decide-document/"
md_url: "https://www.nutrient.io/guides/java/extraction/decide-document.md"
last_updated: "2026-10-27T00:00:00.000Z"
description: "Get yes/no, multiple-choice, and ordinal decisions from JSON data using Nutrient Java SDK, with confidence scores and probability distributions for each answer."
---

# Making decisions from JSON data

Not every judgment call fits a classification label or a structured extraction field. "Is this total plausible?", "Which expense category applies?", "How confident are we this clause is a liability waiver?" — these are calibrated yes/no, multiple-choice, or ordinal decisions over state *you* already have, not a document Nutrient needs to open and parse itself.

This sample shows how to get calibrated decisions from Nutrient's decision model using Nutrient Java SDK. You supply the shared state and the questions to ask against it directly as JSON; the SDK returns a calibrated answer — with a confidence and the full probability distribution — for each question. It runs locally.

Decision API is available in Nutrient Java SDK 2.1.13 and later.

[Download sample](https://www.nutrient.io/downloads/samples/java/decide-document.zip)

## How Nutrient helps

The decision API is a generic pass-through onto Nutrient's decision model — no document, schema, or template list is involved. The SDK handles:

- Rendering the shared state and each question into the model's expected prompt format

- Embedding any inline images in the state at the position they appear

- Reading one label token's logits per question — the model never generates text, so answers are deterministic reads, not samples

- Calibrating the raw result into a confidence and a full probability distribution per question

- Serializing every answer plus token usage to JSON

## Questions and state

`stateJson` is the shared context every question is evaluated against — any JSON object, array, or plain string. Embed images anywhere in the structure as `{"type": "image", "source": "data:<mime>;base64,<bytes>"}`; the SDK walks the whole state, substitutes each with the model's media marker, and sends the image bytes alongside, in encounter order.

`questionsJson` is an array of `{id, type, instructions, options?}`:

- `type: "noul"` — a yes/no judgment. `options` can be omitted (default true/false wording) or given as exactly two entries for custom wording.

- `type: "choice"` — pick one of 2+ `options`, each `{key, description}`.

- `type: "score"` — an ordinal judgment over 2+ unlabeled `options`, numbered low to high by position.

Every question is answered independently in the same call, against the same shared state.

The decision API requires the decision model feature in your license.

## Complete implementation

Declare the sample's package:

```java

package io.nutrient.Sample;

```

Import the classes used in the sample:

```java

import io.nutrient.sdk.Vision;
import io.nutrient.sdk.exceptions.NutrientException;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

```

## Building the state and questions

Decide works on plain JSON you already have — here, a parsed invoice record instead of a loaded document. This sample builds the JSON by hand to keep the dependency list minimal; use your preferred JSON library in production code:

```java

public class DecideDocument {
    public static void main(String[] args) {
        String stateJson =
            "{" +
            "  \"invoice\": {" +
            "    \"vendor\": \"Acme Consulting LLC\"," +
            "    \"total\": 1204.50," +
            "    \"currency\": \"USD\"," +
            "    \"description\": \"Software and subscriptions renewal\"" +
            "  }" +
            "}";

        String questionsJson =
            "[" +
            "  {" +
            "    \"id\": \"amount_reasonable\"," +
            "    \"type\": \"noul\"," +
            "    \"instructions\": \"Is the total a plausible amount for this invoice?\"" +
            "  }," +
            "  {" +
            "    \"id\": \"category\"," +
            "    \"type\": \"choice\"," +
            "    \"instructions\": \"Which expense category applies?\"," +
            "    \"options\": [" +
            "      { \"key\": \"travel\", \"description\": \"Travel and lodging\" }," +
            "      { \"key\": \"software\", \"description\": \"Software and subscriptions\" }," +
            "      { \"key\": \"office_supplies\", \"description\": \"Office supplies and equipment\" }" +
            "    ]" +
            "  }" +
            "]";

```

## Getting the decisions

Call the static `Vision.decide(stateJson, questionsJson)`:

```java

        try {
            String resultJson = Vision.decide(stateJson, questionsJson);

            Files.writeString(Path.of("output.json"), resultJson);
        } catch (NutrientException | IOException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

```

## Understanding the output

`decide()` returns JSON with top-level `answers` and `usage` objects:

- **`answers`** — one entry per question `id`. Each carries:
  - **`type`** — the question's type (`noul`, `choice`, or `score`), echoed back.
  - **`chosenIndex`** — the index of the selected option.
  - **`chosenKey`** — the option's `key` (`"true"`/`"false"` for `noul`; a lettered label like `"A"` for `score`, since score options have no `key`).
  - **`confidence`** — the calibrated probability of the chosen answer.
  - **`probabilities`** — the full calibrated probability distribution over every option, in option order.

- **`usage`** — `promptTokens` (exact, from the model's own decode) and `outputTokens` (one per question answered — `decide()` never generates text, so this counts work done, not text length).

## Choosing question types

Use `noul` for a single yes/no judgment, `choice` when the answer is one of several discrete categories, and `score` for an ordinal judgment (low to high) where the options don't need individual names. Batching related judgments into fewer, larger `choice`/`score` questions is more efficient than asking many separate `noul` questions, since each question re-evaluates the full shared state.

## Error handling

Vision API throws `VisionException` (a `NutrientException`) when a decision call fails.

Common failure scenarios include:

- `stateJson` or `questionsJson` is empty or missing

- The decision model is missing or inaccessible, or the feature isn't licensed

- A question's `options` are malformed for its `type` (for example, `choice` with fewer than two options)

In production code:

- Catch `NutrientException`.

- Return a clear error message.

- Log failure details for debugging.

## Conclusion

The workflow for getting decisions is:

1. Build the shared state as a JSON value — any object, array, or string you already have.

2. Build the questions array, choosing `noul`, `choice`, or `score` per judgment.

3. Call `Vision.decide()` with both payloads as JSON strings.

4. Write the JSON result to a file, then read each question's `chosenKey` and `confidence` for downstream routing.

5. Handle `NutrientException` for robust error recovery.

For related document workflows, refer to the [Java SDK guides](https://www.nutrient.io/guides/java.md).

Download [this ready-to-use sample package](https://www.nutrient.io/downloads/samples/java/decide-document.zip) to explore the decision API.
---

## Related pages

- [Nutrient Java SDK extraction guides](/guides/java/extraction.md)
- [Applying OCR to a PDF page](/guides/java/extraction/apply-ocr-to-pdf-page.md)
- [Applying OCR to a PDF document](/guides/java/extraction/apply-ocr-to-pdf.md)
- [Classifying documents](/guides/java/extraction/classify-document.md)
- [Generating image descriptions using Claude](/guides/java/extraction/describe-image-with-claude.md)
- [Describe images with a custom local AI endpoint](/guides/java/extraction/describe-image-with-custom-local-ai.md)
- [Generating image descriptions using local AI](/guides/java/extraction/describe-image-with-local-ai.md)
- [Generating image descriptions using OpenAI](/guides/java/extraction/describe-image-with-openai.md)
- [Detecting document language](/guides/java/extraction/detect-document-language.md)
- [Extracting data from images using ICR](/guides/java/extraction/extract-data-from-image-icr.md)
- [Extracting data from images using OCR](/guides/java/extraction/extract-data-from-image-ocr.md)
- [Extracting data from images using vision language models](/guides/java/extraction/extract-data-from-image-vlm.md)
- [Extracting data from specific pages](/guides/java/extraction/extract-data-from-specific-pages.md)
- [Extracting form fields from images](/guides/java/extraction/extract-form-fields-from-image.md)
- [Extracting structured data from documents](/guides/java/extraction/extract-structured-data.md)
- [Generating extraction schemas](/guides/java/extraction/generate-extraction-schema.md)
- [Extracting JSON data from a PDF document](/guides/java/extraction/json-data-extraction.md)
- [Labeling form fields with a vision language model](/guides/java/extraction/label-form-fields-with-vlm.md)
- [Opening password-protected PDFs](/guides/java/extraction/open-password-protected-pdf.md)
- [Extracting text from PDF documents](/guides/java/extraction/pdf-to-text.md)
- [Reading barcodes with vision extraction](/guides/java/extraction/read-barcodes-with-vision.md)
- [Extracting text from multilingual images](/guides/java/extraction/read-text-from-image-multi-language.md)
- [Extracting text from images](/guides/java/extraction/read-text-from-image.md)
- [Searching document text](/guides/java/extraction/search-document-text.md)
- [Speeding up first ICR operation by predownloading models](/guides/java/extraction/speed-up-first-icr-by-downloading-requirements.md)
- [Split documents](/guides/java/extraction/split-document.md)

