# Files

> Upload one file or many, then attach the IDs to a chat request.

Source: https://maincode.com/docs/python-client-sdk-files
Section: Client SDK · Matilda documentation

---

## `files.upload(file, ...)`

Uploads a single file by path. Files at or above the chunked threshold (`MatildaConfig.chunked_threshold`, 16 MiB default) use the parallel multipart protocol; smaller files use single-shot upload.

```python title="upload.py"
async def main():
    async with MatildaClient(token="...") as client:
        result = await client.files.upload(
            "hello.txt",
            content_type="text/plain",
            on_progress=lambda pct: print(f"Upload: {pct}%"),
        )
        print(f"File ID: {result.file_id}, Status: {result.status}")
```

### Parameters

| Field | Type | Description |
| - | - | - |
| `file` | `str \| Path` | Path to the file to upload. |
| `content_type` | `str` | MIME type. Defaults to 'application/octet-stream'. |
| `filename` | `str \| None` | Override the reported filename. Defaults to the path basename. |
| `on_progress` | `Callable[[int], None] \| None` | Progress callback (0–100). |

Returns `FileComplete`:

```python
@dataclass
class FileComplete:
    file_id: str
    status: str  # 'pending' | 'scanning' | 'processing' | 'ready' | 'failed' | 'rejected'
```

## `files.upload_many(files, *, file_concurrency=3, **kwargs)`

Uploads multiple files in parallel (auto-selecting single-shot vs chunked per file). One file's failure does not abort the others — per-file outcomes arrive in the result list, in input order, as either `FileComplete` or `UploadError`.

```python title="upload_many.py"
async def main():
    async with MatildaClient(token="...") as client:
        results = await client.files.upload_many(["doc1.txt", "doc2.txt"])
        for i, result in enumerate(results):
            if isinstance(result, UploadError):
                print(f"File {i} failed: {result}")
            else:
                print(f"File {i}: {result.file_id} ({result.status})")
```

Returns `list[FileComplete | UploadError]`.

## `files.retrieve(file_id)`

Retrieves metadata for a previously uploaded file.

```python
file = await client.files.retrieve("file-abc123")
print(f"{file['filename']} — {file['status']} ({file['sizeBytes']} bytes)")
if file.get("extractedText"):
    print(f"Extracted: {file['extractedText'][:100]}...")
```

Returns a `dict` (a `FileAttachment`: `id`, `filename`, `contentType`, `sizeBytes`, `status`, optional `extractedText`, `thumbnailUrl`, `localUri`, `failureReason`, `createdAt`).

## Using files in chat

Upload a file, then reference its `file_id` in a chat message:

```python title="attach.py"
async def main():
    async with MatildaClient(token="...") as client:
        upload = await client.files.upload("report.pdf", content_type="application/pdf")

        response = await client.chat.create(
            input="Summarise this report.",
            file_ids=[upload.file_id],
        )
        print(response.output_text)
```
