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

# Schemas

> Define what to extract with typed JSON schemas, Pydantic models, or Zod objects

Every API call takes a `schema` parameter that describes the fields you want. You can define schemas three ways: raw JSON, Pydantic models (Python), or Zod objects (TypeScript).

## Typed JSON schema

Each field is an object with a `type` and `description`:

```json theme={null}
{
  "vendor": {"type": "string", "description": "Company name on the invoice"},
  "total": {"type": "number", "description": "Total amount due including tax"},
  "is_paid": {"type": "boolean", "description": "Whether the invoice is marked as paid"}
}
```

### Supported types

| Type      | Returns       | Example value                           |
| --------- | ------------- | --------------------------------------- |
| `string`  | Text          | `"Acme Corp"`                           |
| `number`  | Float         | `1234.56`                               |
| `integer` | Whole number  | `42`                                    |
| `boolean` | true/false    | `true`                                  |
| `array`   | List          | `[{"item": "Widget", "qty": 3}]`        |
| `object`  | Nested object | `{"street": "123 Main", "city": "NYC"}` |

### Enums

Constrain a field to specific allowed values:

```json theme={null}
{
  "status": {
    "type": "string",
    "enum": ["paid", "unpaid", "overdue"],
    "description": "Payment status"
  }
}
```

### Required fields

Mark fields as required — the response will set `success: false` if any required field is missing:

```json theme={null}
{
  "invoice_number": {
    "type": "string",
    "description": "Invoice reference number",
    "required": true
  }
}
```

### Arrays

Extract lists of items with a defined shape:

```json theme={null}
{
  "line_items": {
    "type": "array",
    "description": "Each line item on the invoice",
    "items": {
      "type": "object",
      "properties": {
        "description": {"type": "string", "description": "Item description"},
        "quantity": {"type": "integer", "description": "Quantity"},
        "unit_price": {"type": "number", "description": "Price per unit"}
      }
    }
  }
}
```

### Nested objects

```json theme={null}
{
  "vendor": {
    "type": "object",
    "description": "Vendor information",
    "properties": {
      "name": {"type": "string", "description": "Company name"},
      "address": {"type": "string", "description": "Full address"},
      "tax_id": {"type": "string", "description": "Tax identification number"}
    }
  }
}
```

## Pydantic models (Python)

Pass a Pydantic `BaseModel` class directly as the schema. The SDK converts it automatically — including nested models, `Optional` fields, `Literal` enums, and `Field(description=...)`.

```python theme={null}
from pydantic import BaseModel, Field
from typing import Optional
from enum import Enum

class Status(str, Enum):
    paid = "paid"
    unpaid = "unpaid"
    overdue = "overdue"

class LineItem(BaseModel):
    description: str = Field(description="Item description")
    quantity: int = Field(description="Quantity")
    unit_price: float = Field(description="Price per unit")

class Invoice(BaseModel):
    invoice_number: str = Field(description="The invoice number")
    vendor: str = Field(description="Company name")
    total: float = Field(description="Total amount due")
    status: Status = Field(description="Payment status")
    notes: Optional[str] = Field(default=None, description="Additional notes")
    line_items: list[LineItem] = Field(description="Invoice line items")

result = client.extract(file="invoice.pdf", schema=Invoice)
```

This generates the equivalent typed JSON schema behind the scenes. Every Pydantic feature maps to a schema type:

| Pydantic                      | Schema type              |
| ----------------------------- | ------------------------ |
| `str`                         | `string`                 |
| `float`                       | `number`                 |
| `int`                         | `integer`                |
| `bool`                        | `boolean`                |
| `list[T]`                     | `array` with items       |
| Nested `BaseModel`            | `object` with properties |
| `Optional[T]`                 | Nullable field           |
| `Literal["a", "b"]` or `Enum` | `string` with `enum`     |
| `Field(description="...")`    | Field description        |

## Zod schemas (TypeScript)

Use `fromZod()` to convert a Zod object schema. Supports `z.string()`, `z.number()`, `z.boolean()`, `z.array()`, `z.object()`, `z.enum()`, and `.describe()`.

```typescript theme={null}
import { TheDriveAI, fromZod } from "@thedriveai/sdk";
import { z } from "zod";

const LineItem = z.object({
  description: z.string().describe("Item description"),
  quantity: z.number().describe("Quantity"),
  unit_price: z.number().describe("Price per unit"),
});

const Invoice = z.object({
  invoice_number: z.string().describe("The invoice number"),
  vendor: z.string().describe("Company name"),
  total: z.number().describe("Total amount due"),
  status: z.enum(["paid", "unpaid", "overdue"]).describe("Payment status"),
  notes: z.string().optional().describe("Additional notes"),
  line_items: z.array(LineItem).describe("Invoice line items"),
});

const result = await client.extract({
  file: readFileSync("invoice.pdf"),
  schema: fromZod(Invoice),
});
```

| Zod                | Schema type              |
| ------------------ | ------------------------ |
| `z.string()`       | `string`                 |
| `z.number()`       | `number`                 |
| `z.boolean()`      | `boolean`                |
| `z.array(T)`       | `array` with items       |
| `z.object({...})`  | `object` with properties |
| `z.enum([...])`    | `string` with `enum`     |
| `.optional()`      | Nullable field           |
| `.describe("...")` | Field description        |

## Type guarantees

When you define a field as `"type": "number"`, the API guarantees the returned value is a JSON number — not a string like `"$1,234.56"`. The AI parses, cleans, and type-coerces values automatically.

If a field can't be found in the document, it returns `null` (not an empty string or zero).

## Limits

* Maximum **10 top-level fields** per request (excluding `_`-prefixed meta keys)
* No limit on nested properties within arrays or objects
* Descriptions improve accuracy — always include them
