> ## 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.

# Upload

> Stage a file for parse, extract, split, classify, or ground

`documents.create_upload` stages bytes for a **granular** operation. The handle
is single-use: bytes are deleted when the job that reads them finishes.
Default TTL is 24 hours; the cap is 7 days.

For a durable corpus, use [workspaces](/sdks/python/workspaces).

```python theme={"dark"}
from pathlib import Path

from ndi_sdk import NdiClient

with NdiClient() as client:
    upload = client.documents.create_upload(Path("report.pdf"))
    print(upload.upload_id, upload.expires_at)
    job = client.jobs.wait(client.documents.parse(upload, wait_seconds=30).job_id)
    print(job.result.markdown)
```

## Method signature

```text theme={"dark"}
def create_upload(
    content: str | Path | bytes | BinaryIO,
    *,
    file_name: str | None = None,
    ttl_seconds: int | None = None,
) -> UploadResponse
```

### Parameters

| Parameter     | Type                                       | Required | Description                              |
| ------------- | ------------------------------------------ | -------- | ---------------------------------------- |
| `content`     | path string, `Path`, bytes, or binary file | Yes      | File to stage                            |
| `file_name`   | `str \| None`                              | No       | Override the name (needed for raw bytes) |
| `ttl_seconds` | `int \| None`                              | No       | Unused-upload ceiling; omit for 24 hours |

### Returns

`UploadResponse`: `upload_id`, `file_name`, `size_bytes`, `content_hash`,
`expires_at`. Pass the object itself as `source` to parse/extract/split/classify/ground.

## Options

```python theme={"dark"}
upload = client.documents.create_upload(Path("report.pdf"), ttl_seconds=3600)
```

```python theme={"dark"}
upload = client.documents.create_upload(
    data,
    file_name="report.pdf",
)
```

## Async

```python theme={"dark"}
import asyncio
from pathlib import Path

from ndi_sdk import AsyncNdiClient


async def main() -> None:
    async with AsyncNdiClient() as client:
        upload = await client.documents.create_upload(Path("report.pdf"))
        print(upload.upload_id)


asyncio.run(main())
```

## Errors

* `file_too_large` (413) — over the upload size cap
* `upload_expired` (409) — handle expired or already consumed
* `unsupported_file_type` — usually raised by the next operation, not upload

See [Upload guide](/guides/upload) and [Sources](/concepts/sources-and-uploads).
