---
title: Getting Started | Developer Documentation
description: Use the client SDK to classify documents with natural-language rules, including file uploads, job polling, and reading results.
---

This guide shows how to classify documents using the SDK. You will:

- Create classification rules
- Upload files
- Submit a classify job
- Read predictions (type, confidence, reasoning)

The SDK is available in [llama-parse-py](https://github.com/run-llama/llama-parse-py), [llama-parse-ts](https://github.com/run-llama/llama-parse-ts), [llama-parse-go](https://github.com/run-llama/llama-parse-go), and [llama-parse-java](https://github.com/run-llama/llama-parse-java), plus the [llama-parse-cli](https://github.com/run-llama/llama-parse-cli) command-line tool.

## Setup

First, [get an API key](../../general/api_key) and record it for safe keeping.

You can set this as an environment variable `LLAMA_CLOUD_API_KEY` or pass it directly to the SDK at runtime.

Then, install dependencies:

- [Python](#tab-panel-95)
- [TypeScript](#tab-panel-96)
- [Go](#tab-panel-97)
- [Java](#tab-panel-98)
- [CLI](#tab-panel-99)

Terminal window

```
pip install llama-cloud>=2.8
```

Terminal window

```
npm install @llamaindex/llama-cloud
```

Terminal window

```
go get github.com/run-llama/llama-parse-go
```

build.gradle.kts

```
implementation("ai.llamaindex:llama-cloud:1.3.0")
```

Terminal window

```
go install github.com/run-llama/llama-parse-cli/cmd/llp@latest
```

## Quick start

Using the classify API consists of a few main steps:

1. Upload a file and get its ID
2. Create a classify job with your rules, passing that ID as `file_input`
3. Wait for the job to finish
4. Read the result

`file_input` also accepts a parse job ID, so a document you have already parsed can be classified without uploading or re-parsing it.

The SDK provides a convenience method that handles all of these steps in one call:

- [Python](#tab-panel-100)
- [TypeScript](#tab-panel-101)
- [Go](#tab-panel-102)
- [Java](#tab-panel-103)
- [CLI](#tab-panel-104)

```
import os
from llama_cloud import LlamaCloud, AsyncLlamaCloud


# For async usage, use `AsyncLlamaCloud()`
client = LlamaCloud(api_key=os.environ["LLAMA_CLOUD_API_KEY"])


# Upload a file
file_obj = client.files.create(file="/path/to/doc1.pdf", purpose="classify")


# Classify and wait for completion
job = client.classify.run(
    file_input=file_obj.id,
    configuration={
        "rules": [
            {
                "type": "invoice",
                "description": "Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.",
            },
            {
                "type": "receipt",
                "description": "Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.",
            },
        ],
        "parsing_configuration": {
            "lang": "en",
            "max_pages": 5,            # optional, parse at most 5 pages
            # "target_pages": "1,3",   # optional, parse only specific pages (1-based)
        },
    },
)


# `run` raises PollingError if the job fails, so reaching here means it succeeded
print(f"Classified type: {job.result.type}")
print(f"Confidence: {job.result.confidence}")
print(f"Reasoning: {job.result.reasoning}")
```

```
import LlamaCloud from '@llamaindex/llama-cloud';
import fs from 'fs';


const client = new LlamaCloud({ apiKey: process.env.LLAMA_CLOUD_API_KEY });


// Upload a file
const fileObj = await client.files.create({
    file: fs.createReadStream('/path/to/doc1.pdf'),
    purpose: "classify",
});


// Classify and wait for completion
const job = await client.classify.run({
    file_input: fileObj.id,
    configuration: {
        rules: [
            {
                type: 'invoice',
                description: 'Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.',
            },
            {
                type: 'receipt',
                description: 'Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.',
            },
        ],
        parsing_configuration: {
            lang: 'en',
            max_pages: 5,
            // target_pages: "1,3",  // Optional: specific pages (1-based)
        },
    },
});


// `run` throws if the job fails, so reaching here means it succeeded
console.log(`Classified type: ${job.result!.type}`);
console.log(`Confidence: ${job.result!.confidence}`);
console.log(`Reasoning: ${job.result!.reasoning}`);
```

```
package main


import (
    "context"
    "fmt"
    "log"
    "os"
    "time"


    llamacloud "github.com/run-llama/llama-parse-go"
)


func main() {
    ctx := context.Background()
    client := llamacloud.NewClient()


    // Upload a file
    f, err := os.Open("/path/to/doc1.pdf")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()


    fileObj, err := client.Files.New(ctx, llamacloud.FileNewParams{
        File:    f,
        Purpose: "classify",
    })
    if err != nil {
        log.Fatal(err)
    }


    // Create a classify job
    job, err := client.Classify.New(ctx, llamacloud.ClassifyNewParams{
        ClassifyCreateRequest: llamacloud.ClassifyCreateRequestParam{
            FileInput: llamacloud.String(fileObj.ID),
            Configuration: llamacloud.ClassifyConfigurationParam{
                Rules: []llamacloud.ClassifyConfigurationRuleParam{
                    {
                        Type:        "invoice",
                        Description: "Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.",
                    },
                    {
                        Type:        "receipt",
                        Description: "Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.",
                    },
                },
                ParsingConfiguration: llamacloud.ClassifyConfigurationParsingConfigurationParam{
                    Lang:     llamacloud.String("en"),
                    MaxPages: llamacloud.Int(5),            // optional, parse at most 5 pages
                    // TargetPages: llamacloud.String("1,3"), // optional, parse only specific pages (1-based)
                },
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }


    // Poll until the job reaches a terminal state
    result, err := client.Classify.Get(ctx, job.ID, llamacloud.ClassifyGetParams{})
    if err != nil {
        log.Fatal(err)
    }
    for result.Status == llamacloud.ClassifyGetResponseStatusPending ||
        result.Status == llamacloud.ClassifyGetResponseStatusRunning {
        time.Sleep(2 * time.Second)
        result, err = client.Classify.Get(ctx, job.ID, llamacloud.ClassifyGetParams{})
        if err != nil {
            log.Fatal(err)
        }
    }


    if !result.JSON.Result.Valid() {
        log.Fatalf("Classification failed: %s", result.ErrorMessage)
    }
    fmt.Printf("Classified type: %s\n", result.Result.Type)
    fmt.Printf("Confidence: %v\n", result.Result.Confidence)
    fmt.Printf("Reasoning: %s\n", result.Result.Reasoning)
}
```

```
import ai.llamaindex.llamacloud.client.LlamaCloudClient;
import ai.llamaindex.llamacloud.client.okhttp.LlamaCloudOkHttpClient;
import ai.llamaindex.llamacloud.models.classify.ClassifyConfiguration;
import ai.llamaindex.llamacloud.models.classify.ClassifyCreateRequest;
import ai.llamaindex.llamacloud.models.classify.ClassifyCreateResponse;
import ai.llamaindex.llamacloud.models.classify.ClassifyGetResponse;
import ai.llamaindex.llamacloud.models.files.FileCreateParams;
import ai.llamaindex.llamacloud.models.files.FileCreateResponse;
import java.nio.file.Paths;
import java.util.Arrays;


public class ClassifyQuickStart {
    public static void main(String[] args) throws Exception {
        LlamaCloudClient client = LlamaCloudOkHttpClient.fromEnv();


        // Upload a file
        FileCreateResponse fileObj = client.files().create(
            FileCreateParams.builder()
                .file(Paths.get("/path/to/doc1.pdf"))
                .purpose("classify")
                .build());


        // Create a classify job
        ClassifyCreateResponse job = client.classify().create(
            ClassifyCreateRequest.builder()
                .fileInput(fileObj.id())
                .configuration(ClassifyConfiguration.builder()
                    .rules(Arrays.asList(
                        ClassifyConfiguration.Rule.builder()
                            .type("invoice")
                            .description("Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.")
                            .build(),
                        ClassifyConfiguration.Rule.builder()
                            .type("receipt")
                            .description("Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.")
                            .build()))
                    .parsingConfiguration(ClassifyConfiguration.ParsingConfiguration.builder()
                        .lang("en")
                        .maxPages(5L)               // optional, parse at most 5 pages
                        // .targetPages("1,3")      // optional, parse only specific pages (1-based)
                        .build())
                    .build())
                .build());


        // Poll until the job reaches a terminal state
        ClassifyGetResponse result = client.classify().get(job.id());
        while (result.status().equals(ClassifyGetResponse.Status.PENDING)
            || result.status().equals(ClassifyGetResponse.Status.RUNNING)) {
            Thread.sleep(2000);
            result = client.classify().get(job.id());
        }


        if (!result.result().isPresent()) {
            System.out.println("Classification failed: " + result.errorMessage().orElse(""));
        } else {
            System.out.println("Classified type: " + result.result().get().type().orElse(""));
            System.out.println("Confidence: " + result.result().get().confidence());
            System.out.println("Reasoning: " + result.result().get().reasoning());
        }
    }
}
```

Terminal window

```
export LLAMA_CLOUD_API_KEY="llx-..."


# Upload a file
FILE_ID=$(llp files create --file /path/to/doc1.pdf --purpose classify | jq -r '.id')


# Create a classify job
JOB_ID=$(llp classify create \
  --file-input "$FILE_ID" \
  --configuration '{rules: [{type: invoice, description: "Documents that contain an invoice number, invoice date, bill-to section, and line items with totals."}, {type: receipt, description: "Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page."}], parsing_configuration: {lang: en, max_pages: 5}}' \
  | jq -r '.id')


# Poll until the job reaches a terminal state
while true; do
  RESULT=$(llp classify get "$JOB_ID")
  STATUS=$(echo "$RESULT" | jq -r '.status')
  [ "$STATUS" = "PENDING" ] || [ "$STATUS" = "RUNNING" ] || break
  sleep 2
done


echo "$RESULT" | jq -r '.result.type, .result.confidence, .result.reasoning'
```

## Step-by-step (manual polling)

You can also run each step individually if you need more control:

- [Python](#tab-panel-105)
- [TypeScript](#tab-panel-106)
- [Go](#tab-panel-107)
- [Java](#tab-panel-108)
- [CLI](#tab-panel-109)

```
import os
import time
from llama_cloud import LlamaCloud


client = LlamaCloud(api_key=os.environ["LLAMA_CLOUD_API_KEY"])


# Upload a file
file_obj = client.files.create(file="/path/to/doc1.pdf", purpose="classify")


# Create a classify job
job = client.classify.create(
    file_input=file_obj.id,
    configuration={
        "rules": [
            {
                "type": "invoice",
                "description": "Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.",
            },
            {
                "type": "receipt",
                "description": "Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.",
            },
        ],
    },
)


# Poll until the job reaches a terminal state
result = client.classify.get(job.id)
while result.status in ("PENDING", "RUNNING"):
    time.sleep(2)
    result = client.classify.get(job.id)


# `get` returns the result inline once the job is COMPLETED
if result.result is None:
    print(f"Classification failed: {result.error_message}")
else:
    print(f"Classified type: {result.result.type}")
    print(f"Confidence: {result.result.confidence}")
    print(f"Reasoning: {result.result.reasoning}")
```

```
import LlamaCloud from '@llamaindex/llama-cloud';
import fs from 'fs';


const client = new LlamaCloud({ apiKey: process.env.LLAMA_CLOUD_API_KEY });


// Upload a file
const fileObj = await client.files.create({
    file: fs.createReadStream('/path/to/doc1.pdf'),
    purpose: "classify",
});


// Create a classify job
const job = await client.classify.create({
    file_input: fileObj.id,
    configuration: {
        rules: [
            {
                type: 'invoice',
                description: 'Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.',
            },
            {
                type: 'receipt',
                description: 'Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.',
            },
        ],
    },
});


// Poll until the job reaches a terminal state
let result = await client.classify.get(job.id);
while (result.status === 'PENDING' || result.status === 'RUNNING') {
    await new Promise((r) => setTimeout(r, 2000));
    result = await client.classify.get(job.id);
}


// `get` returns the result inline once the job is COMPLETED
if (!result.result) {
    console.log(`Classification failed: ${result.error_message}`);
} else {
    console.log(`Classified type: ${result.result.type}`);
    console.log(`Confidence: ${result.result.confidence}`);
    console.log(`Reasoning: ${result.result.reasoning}`);
}
```

```
package main


import (
    "context"
    "fmt"
    "log"
    "os"
    "time"


    llamacloud "github.com/run-llama/llama-parse-go"
)


func main() {
    ctx := context.Background()
    client := llamacloud.NewClient()


    // Upload a file
    f, err := os.Open("/path/to/doc1.pdf")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()


    fileObj, err := client.Files.New(ctx, llamacloud.FileNewParams{
        File:    f,
        Purpose: "classify",
    })
    if err != nil {
        log.Fatal(err)
    }


    // Create a classify job
    job, err := client.Classify.New(ctx, llamacloud.ClassifyNewParams{
        ClassifyCreateRequest: llamacloud.ClassifyCreateRequestParam{
            FileInput: llamacloud.String(fileObj.ID),
            Configuration: llamacloud.ClassifyConfigurationParam{
                Rules: []llamacloud.ClassifyConfigurationRuleParam{
                    {
                        Type:        "invoice",
                        Description: "Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.",
                    },
                    {
                        Type:        "receipt",
                        Description: "Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.",
                    },
                },
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }


    // Poll until the job reaches a terminal state
    result, err := client.Classify.Get(ctx, job.ID, llamacloud.ClassifyGetParams{})
    if err != nil {
        log.Fatal(err)
    }
    for result.Status == llamacloud.ClassifyGetResponseStatusPending ||
        result.Status == llamacloud.ClassifyGetResponseStatusRunning {
        time.Sleep(2 * time.Second)
        result, err = client.Classify.Get(ctx, job.ID, llamacloud.ClassifyGetParams{})
        if err != nil {
            log.Fatal(err)
        }
    }


    // `Get` returns the result inline once the job is COMPLETED
    if !result.JSON.Result.Valid() {
        fmt.Printf("Classification failed: %s\n", result.ErrorMessage)
    } else {
        fmt.Printf("Classified type: %s\n", result.Result.Type)
        fmt.Printf("Confidence: %v\n", result.Result.Confidence)
        fmt.Printf("Reasoning: %s\n", result.Result.Reasoning)
    }
}
```

```
import ai.llamaindex.llamacloud.client.LlamaCloudClient;
import ai.llamaindex.llamacloud.client.okhttp.LlamaCloudOkHttpClient;
import ai.llamaindex.llamacloud.models.classify.ClassifyConfiguration;
import ai.llamaindex.llamacloud.models.classify.ClassifyCreateRequest;
import ai.llamaindex.llamacloud.models.classify.ClassifyCreateResponse;
import ai.llamaindex.llamacloud.models.classify.ClassifyGetResponse;
import ai.llamaindex.llamacloud.models.files.FileCreateParams;
import ai.llamaindex.llamacloud.models.files.FileCreateResponse;
import java.nio.file.Paths;
import java.util.Arrays;


public class ClassifyStepByStep {
    public static void main(String[] args) throws Exception {
        LlamaCloudClient client = LlamaCloudOkHttpClient.fromEnv();


        // Upload a file
        FileCreateResponse fileObj = client.files().create(
            FileCreateParams.builder()
                .file(Paths.get("/path/to/doc1.pdf"))
                .purpose("classify")
                .build());


        // Create a classify job
        ClassifyCreateResponse job = client.classify().create(
            ClassifyCreateRequest.builder()
                .fileInput(fileObj.id())
                .configuration(ClassifyConfiguration.builder()
                    .rules(Arrays.asList(
                        ClassifyConfiguration.Rule.builder()
                            .type("invoice")
                            .description("Documents that contain an invoice number, invoice date, bill-to section, and line items with totals.")
                            .build(),
                        ClassifyConfiguration.Rule.builder()
                            .type("receipt")
                            .description("Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page.")
                            .build()))
                    .build())
                .build());


        // Poll until the job reaches a terminal state
        ClassifyGetResponse result = client.classify().get(job.id());
        while (result.status().equals(ClassifyGetResponse.Status.PENDING)
            || result.status().equals(ClassifyGetResponse.Status.RUNNING)) {
            Thread.sleep(2000);
            result = client.classify().get(job.id());
        }


        // `get` returns the result inline once the job is COMPLETED
        if (!result.result().isPresent()) {
            System.out.println("Classification failed: " + result.errorMessage().orElse(""));
        } else {
            System.out.println("Classified type: " + result.result().get().type().orElse(""));
            System.out.println("Confidence: " + result.result().get().confidence());
            System.out.println("Reasoning: " + result.result().get().reasoning());
        }
    }
}
```

Terminal window

```
export LLAMA_CLOUD_API_KEY="llx-..."


# Upload a file
FILE_ID=$(llp files create --file /path/to/doc1.pdf --purpose classify | jq -r '.id')


# Create a classify job
JOB_ID=$(llp classify create \
  --file-input "$FILE_ID" \
  --configuration.rules '[{type: invoice, description: "Documents that contain an invoice number, invoice date, bill-to section, and line items with totals."}, {type: receipt, description: "Short purchase receipts, typically from POS systems, with merchant, items and total, often a single page."}]' \
  | jq -r '.id')


# Poll until the job reaches a terminal state
while true; do
  RESULT=$(llp classify get "$JOB_ID")
  STATUS=$(echo "$RESULT" | jq -r '.status')
  [ "$STATUS" = "PENDING" ] || [ "$STATUS" = "RUNNING" ] || break
  sleep 2
done


# `get` returns the result inline once the job is COMPLETED
if [ "$(echo "$RESULT" | jq -r '.result')" = "null" ]; then
  echo "Classification failed: $(echo "$RESULT" | jq -r '.error_message')"
else
  echo "$RESULT" | jq -r '.result.type, .result.confidence, .result.reasoning'
fi
```

## Notes

- Each rule requires a `type` (the label to assign) and a `description` (natural-language description of what content matches). Rule types must be unique within a configuration.
- `parsing_configuration` is optional. Use `lang`, `max_pages`, or `target_pages` to control how documents are parsed before classification.
- `target_pages` is a comma-separated string of 1-based page numbers or ranges (e.g., `"1,3,5-7"`).
- Each job classifies a single document. To classify several files, submit one job per file.
- A failed or cancelled job has no `result` — check `status` before reading it, and use `error_message` for the reason.
- Job statuses: `PENDING`, `RUNNING`, `COMPLETED`, `FAILED`, `CANCELLED`.
- Instead of passing `configuration` inline, you can pass a `configuration_id` to reuse a saved configuration.

## Tips for writing good rules

- Be specific about content features that distinguish the type.
- Include key fields the document usually contains (e.g., invoice number, total amount).
- Add multiple rules when needed to cover distinct patterns.
- Start simple, test on a small set, then refine.
