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

# Upload Documents

> Upload text documents using the Python client

## documents.upload

Uploads one or more documents to a **text** namespace. Each document is embedded with the configured embedding provider and stored for semantic search. The upload runs asynchronously — poll `client.documents.upload_job_status` with the returned `job_id`.

```python theme={null}
client.documents.upload(
    namespace_name: str,
    *,
    documents: list[dict],
) -> dict[str, Any]
```

<Note>
  The `*` means `documents` is **keyword-only**. Extra fields on each document (for example `team`, `source`) are stored as metadata for search filters (`#team:ai` in the query).
</Note>

**API:** `POST /namespaces/{namespace_name}/documents` — see [Upload documents](/on-prem/api-references/data/upload-documents)

### Parameters

<ParamField path="namespace_name" type="string" required>
  Target text namespace.
</ParamField>

<ParamField body="documents" type="array" required>
  Non-empty array of document objects.
</ParamField>

<ParamField body="documents[].id" type="string" required>
  Item id, unique within this namespace.
</ParamField>

<ParamField body="documents[].text" type="string" required>
  Document text to embed and store.
</ParamField>

<ParamField body="documents[].{metadata}" type="any">
  Optional additional keys on each document are saved as metadata (for example `"team": "ai"`).
</ParamField>

### Examples

```python theme={null}
from moorcheh import MoorchehClient, MoorchehApiError

with MoorchehClient("http://localhost:8080") as client:
    try:
        resp = client.documents.upload(
            "my-documents",
            documents=[
                {
                    "id": "doc-1",
                    "text": "Moorcheh on-prem retrieval test",
                    "team": "ai",
                },
            ],
        )
        job_id = resp["job_id"]
    except MoorchehApiError as e:
        if e.is_item_limit_exceeded:
            print(e.body)  # items, max_items, requested_new
        else:
            raise
```

Poll with [documents.upload\_job\_status](/on-prem/python-client/data/upload-job-status).

## Returns

<ResponseField name="status" type="string">
  `"success"` when the upload job was started.
</ResponseField>

<ResponseField name="message" type="string">
  Human-readable result description.
</ResponseField>

<ResponseField name="job_id" type="string">
  Id of the async upload job. Poll [documents.upload\_job\_status](/on-prem/python-client/data/upload-job-status) with this value.
</ResponseField>

<ResponseField name="namespace_name" type="string">
  Namespace the documents are being uploaded to.
</ResponseField>

<ResponseField name="total" type="number">
  Number of documents accepted into the upload job.
</ResponseField>

<ResponseField name="items" type="number">
  Current total item count on the instance. Present on **409** item limit errors in `MoorchehApiError.body`.
</ResponseField>

<ResponseField name="max_items" type="number">
  Global item cap for this instance. Present on **409** item limit errors.
</ResponseField>

<ResponseField name="requested_new" type="number">
  Number of new item ids in the request that would exceed the cap. Present on **409** item limit errors.
</ResponseField>

```python Example return value theme={null}
{
  "status": "success",
  "message": "Documents upload started. Poll job status for progress.",
  "job_id": "job-a0e3d54b9d0d4616949474697308a39c",
  "namespace_name": "my-documents",
  "total": 1,
}
```

### Error Handling

Non-2xx responses raise `MoorchehApiError`. Use `e.is_item_limit_exceeded` for **409** quota errors.

```python theme={null}
from moorcheh import MoorchehClient, MoorchehApiError

try:
    with MoorchehClient() as client:
        client.documents.upload("my-documents", documents=[...])
except MoorchehApiError as e:
    print(e.status_code, e.body)
```

| Status | Cause                                                           |
| ------ | --------------------------------------------------------------- |
| 400    | Empty `documents`, missing `id`/`text`, or wrong namespace type |
| 404    | Namespace not found                                             |
| 409    | Global item limit would be exceeded (job not started)           |

<Warning>
  * At most **100,000 items** total across all namespaces
  * **409** is returned before the job starts if new ids would exceed the cap
  * Re-uploading an existing id in the same namespace updates the item and does not consume extra quota
</Warning>

## Related Operations

* [Upload Job Status](/on-prem/python-client/data/upload-job-status)
* [API: Upload documents](/on-prem/api-references/data/upload-documents)
* [CLI: moorcheh upload-documents](/on-prem/cli/data/upload-documents)
