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

# Classify a document

> Label one file against classes you define

Classify reads the original file. It rejects a `parse_result` source.

<Tabs>
  <Tab title="Python">
    ```python theme={"dark"}
    from ndi_sdk import NdiClient
    from ndi_sdk.models.document_ops import ClassifyClass

    with NdiClient() as client:
        document = client.documents.create_upload("invoice.pdf")
        job = client.jobs.wait(
            client.documents.classify(
                document,
                classes=[
                    ClassifyClass(id="invoice", label="Invoice", description="A supplier invoice"),
                ],
                wait_seconds=30,
            ).job_id
        )
        for unit in job.result.units:
            print(unit.unknown, unit.labels)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={"dark"}
    import { NdiClient } from "ndi-sdk";

    const client = new NdiClient();
    const document = await client.documents.createUpload("invoice.pdf");
    const job = await client.jobs.wait(
      (
        await client.documents.classify(document, {
          classes: [{ id: "invoice", label: "Invoice", description: "A supplier invoice" }],
          wait_seconds: 30,
        })
      ).job_id,
    );
    console.log(job.result);
    ```
  </Tab>

  <Tab title="curl">
    ```bash theme={"dark"}
    UPLOAD_ID=$(curl -s -X POST "$NDI_BASE_URL/v1/uploads" \
      -H "X-API-Key: $NDI_API_KEY" \
      -F "file=@invoice.pdf" | jq -r '.upload_id')

    curl -s -X POST "$NDI_BASE_URL/v1/classify?wait_seconds=60" \
      -H "X-API-Key: $NDI_API_KEY" \
      -H "Content-Type: application/json" \
      -d "{\"source\":{\"type\":\"upload\",\"upload_id\":\"$UPLOAD_ID\"},\"classes\":[{\"id\":\"invoice\",\"label\":\"Invoice\",\"description\":\"A supplier invoice\"}]}"
    ```
  </Tab>
</Tabs>

## Options

* **`granularity`** — `document` (default) or `page`
* **`page_ranges`** — restrict which pages are parsed and classified
* **`unknown_policy`** — `allow` (default) returns an `other` label; `force_best` requires a configured class
* **`output.max_alternatives`** — ranked labels per unit (default 3)
* **`output.include_reason`** — default `true`

Confidence is the fraction of the unit's pages or sheets assigned that label,
not a calibrated model probability.
