# Knowledge API

Manage documents within knowledge bases programmatically. Upload, update, retrieve metadata, and delete documents.

**Required scope**: `knowledge-management`

> **Prerequisite**: Knowledge bases are created in the platform dashboard. See [Knowledge Bases](https://docs.minded.com/platform/knowledge-bases). This API manages documents within existing knowledge bases.

## Document Upload Flow

Uploading a document requires three steps:

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  1. Request     │     │  2. Upload      │     │  3. Complete    │     │  4. Poll        │
│  Upload Link    │────▶│  File           │────▶│  Upload         │────▶│  Status         │
└─────────────────┘     └─────────────────┘     └─────────────────┘     └─────────────────┘
        │                       │                       │                       │
        ▼                       ▼                       ▼                       ▼
   POST /upload-link      PUT to uploadUrl      POST /upload-complete    GET /documents
   Returns: uploadUrl,    Include headers       Returns: status          Check status
   documentId, s3Key      from response         "uploaded"               until "ready"
```

1. **Request upload link** — Call `/knowledge/documents/upload-link` to get a pre-signed upload URL
2. **Upload file** — PUT the file bytes to the returned `uploadUrl` with `requiredHeaders`
3. **Complete upload** — Call `/knowledge/documents/upload-complete` with the `uploadId`
4. **Poll status** — Query `/knowledge/documents` until `status` becomes `ready` or `failed`

## Document Status Values

| Status     | Description                                                 |
| ---------- | ----------------------------------------------------------- |
| `uploaded` | Document uploaded, processing in progress                   |
| `ready`    | Document processed successfully and available for retrieval |
| `failed`   | Processing failed; check error details                      |

## Document Identifiers

Documents can be referenced using two identifiers:

| Identifier         | Description                                                                                                                                                                                                                |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `s3Key`            | System-generated document path. Returned by upload endpoints; use for subsequent operations.                                                                                                                               |
| `customDocumentId` | Optional user-defined identifier. Use this to map documents to your external system IDs (e.g., CRM record ID, ticket ID). When provided during upload, you can use it instead of `s3Key` for update and delete operations. |

## Document Labels (label1 and label2)

Documents support two optional label fields for filtering and organization:

* **`label1`**: Primary classification label
* **`label2`**: Secondary classification label

Both labels use a **`namespace:value`** format to prevent high-cardinality values:

```json
{
  "label1": "dept:support",
  "label2": "lang:en"
}
```

### Label Requirements

* **Format**: Must match `namespace:value` pattern (e.g., `topic:billing`, `tier:premium`)
* **Characters**: Only lowercase letters, numbers, hyphens, and underscores (`[a-z0-9_-]`)
* **Max length**: 50 characters
* **Restrictions**: Cannot contain UUIDs, timestamps, or ISO dates

### Label Examples

**Valid:**

* ✅ `dept:billing`
* ✅ `topic:faq`
* ✅ `lang:en-us`
* ✅ `tier:premium`

**Invalid:**

* ❌ `billing` (missing namespace)
* ❌ `Dept:Billing` (uppercase letters)
* ❌ `user:12345678-1234-1234-1234-123456789012` (UUID pattern)

Use labels to filter documents during retrieval (see [Knowledge Base RAG API](https://docs.minded.com/sdk/knowledge-base-rag)).

***

## Custom Metadata (customMeta1–4)

Documents also support up to **four free-form custom metadata fields** for attaching arbitrary string data.

* **`customMeta1`** through **`customMeta4`**: Any string value, no format restriction

```json
{
  "customMeta1": "DOC-98765",
  "customMeta2": "John Smith",
  "customMeta3": "v2.1",
  "customMeta4": "legal"
}
```

### Custom Metadata Requirements

* **Format**: Free-form string, any value is accepted
* **Max length**: 500 characters per field
* **Not filterable**: Custom metadata cannot be used as query filters (unlike `label1`/`label2`)

### How Custom Metadata is Returned

Custom metadata fields are returned in **every retrieved chunk** alongside the document's text. Consumers can read them from `result.metadata.minded_internal_meta1` through `result.metadata.minded_internal_meta4` in raw retrieval responses.

> **Tip**: Use custom metadata to attach source identifiers, version numbers, author names, or any context you want to surface alongside retrieved chunks — without the strict format requirements of filter labels.

***

## Endpoints

| Method | Endpoint                                      | Description                           |
| ------ | --------------------------------------------- | ------------------------------------- |
| POST   | `/knowledge/documents/upload-link`            | Get pre-signed URL for new document   |
| POST   | `/knowledge/documents/upload-complete`        | Finalize new document upload          |
| POST   | `/knowledge/documents/update/upload-link`     | Get pre-signed URL to update document |
| POST   | `/knowledge/documents/update/upload-complete` | Finalize document update              |
| PATCH  | `/knowledge/documents/metadata`               | Update document metadata only         |
| GET    | `/knowledge/documents`                        | Get document metadata                 |
| DELETE | `/knowledge/documents`                        | Delete a document                     |

***

## Create Upload Link

```http
POST /knowledge/documents/upload-link
```

Generate a pre-signed URL to upload a new document.

### Request Body

| Field              | Type   | Required | Description                                                                      |
| ------------------ | ------ | -------- | -------------------------------------------------------------------------------- |
| `agentId`          | string | Yes      | Agent UUID                                                                       |
| `environment`      | string | Yes      | `development`, `staging`, or `production`                                        |
| `knowledgeBaseId`  | string | Yes      | Knowledge base UUID                                                              |
| `fileName`         | string | Yes      | File name with extension (e.g., `policy.pdf`). If `.zip`, triggers batch import. |
| `label1`           | string | No       | Primary label in `namespace:value` format (e.g., `dept:support`)                 |
| `label2`           | string | No       | Secondary label in `namespace:value` format (e.g., `lang:en`)                    |
| `customMeta1`      | string | No       | Free-form custom metadata field 1 (max 500 chars)                                |
| `customMeta2`      | string | No       | Free-form custom metadata field 2 (max 500 chars)                                |
| `customMeta3`      | string | No       | Free-form custom metadata field 3 (max 500 chars)                                |
| `customMeta4`      | string | No       | Free-form custom metadata field 4 (max 500 chars)                                |
| `customDocumentId` | string | No       | Your external identifier for this document                                       |

### Request Example

```json
{
  "agentId": "your-agent-id",
  "environment": "production",
  "knowledgeBaseId": "kb-abc123",
  "fileName": "refund-policy.pdf",
  "label1": "dept:support",
  "label2": "lang:en",
  "customMeta1": "DOC-98765",
  "customMeta2": "John Smith",
  "customDocumentId": "DOC-12345"
}
```

### Response

```json
{
  "uploadId": "upload-uuid",
  "uploadUrl": "https://storage.example.com/...",
  "expiresIn": 3600,
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy.pdf",
  "documentId": "document-uuid",
  "requiredHeaders": {
    "Content-Type": "application/pdf"
  }
}
```

### Response Fields

| Field             | Type   | Description                                                             |
| ----------------- | ------ | ----------------------------------------------------------------------- |
| `uploadId`        | string | Unique identifier for this upload session                               |
| `uploadUrl`       | string | Pre-signed URL for file upload (expires per `expiresIn`)                |
| `expiresIn`       | number | Seconds until `uploadUrl` expires                                       |
| `s3Key`           | string | Document path; use for subsequent operations                            |
| `documentId`      | string | System-generated document UUID (or your `customDocumentId` if provided) |
| `requiredHeaders` | object | Headers to include when uploading to `uploadUrl`                        |

### Uploading the File

After receiving the response, upload your file:

```bash
curl -X PUT "<uploadUrl>" \
  -H "Content-Type: application/pdf" \
  --data-binary @refund-policy.pdf
```

***

## Complete Upload

```http
POST /knowledge/documents/upload-complete
```

Finalize the upload and trigger document processing.

### Request Body

| Field      | Type   | Required | Description                              |
| ---------- | ------ | -------- | ---------------------------------------- |
| `uploadId` | string | Yes      | The `uploadId` from upload-link response |

### Request Example

```json
{
  "uploadId": "upload-uuid"
}
```

### Response (Document)

```json
{
  "type": "document",
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy.pdf",
  "documentId": "document-uuid",
  "createdAt": "2026-01-15T12:00:00.000Z",
  "updatedAt": "2026-01-15T12:00:00.000Z",
  "status": "uploaded"
}
```

### Response (ZIP Import)

When `fileName` ends with `.zip`, the response indicates a batch import job:

```json
{
  "type": "zip_import",
  "zipJobId": "job-uuid",
  "status": "pending",
  "s3Key": "agents/<agentId>/production/<kbId>/archive.zip"
}
```

### Response Fields

| Field        | Type   | Description                                                      |
| ------------ | ------ | ---------------------------------------------------------------- |
| `type`       | string | `document` for single files, `zip_import` for archives           |
| `s3Key`      | string | Document path; use for subsequent operations                     |
| `documentId` | string | Document UUID (for `document` type)                              |
| `zipJobId`   | string | Import job UUID (for `zip_import` type)                          |
| `status`     | string | Processing status (see [Status Values](#document-status-values)) |
| `createdAt`  | string | ISO 8601 creation timestamp                                      |
| `updatedAt`  | string | ISO 8601 last update timestamp                                   |

### ZIP Import with Per-File Metadata

When uploading a ZIP file, you can include per-file metadata by adding a CSV file to the archive.

**Default Behavior:**

* All files in the ZIP inherit the `label1` and `label2` values from the upload request
* Example: Upload with `label1: "dept:support"` → all files get `dept:support`

**Per-File Metadata (CSV):** Include a `.csv` file in your ZIP with this structure:

```csv
filename,label1,label2
policy.pdf,dept:legal,type:policy
guide.pdf,dept:support,type:guide
faq.html,dept:support,topic:faq
```

**CSV Format:**

* **Header row**: Optional (if present, will be ignored)
* **First column**: File identifier - either:
  * `filename`: Full filename with extension (e.g., `policy.pdf`)
  * `uniqueId`: Your custom document ID (if using `customDocumentId`)
* **Second column**: `label1` value (optional)
* **Third column**: `label2` value (optional)

**Processing Rules:**

1. Files listed in CSV get their specific labels
2. Files NOT in CSV get default labels from upload request
3. Empty label columns in CSV = no label for that field
4. CSV file itself is not processed as a document

**Example ZIP Structure:**

```
documents.zip
├── metadata.csv          ← Per-file labels
├── policy.pdf           ← Gets labels from CSV
├── guide.pdf            ← Gets labels from CSV
└── terms.pdf            ← Gets default labels from upload request
```

**Upload Request:**

```json
{
  "agentId": "your-agent-id",
  "environment": "production",
  "knowledgeBaseId": "kb-abc123",
  "fileName": "documents.zip",
  "label1": "dept:general",
  "label2": "lang:en"
}
```

**Result:**

* `policy.pdf` → `label1: "dept:legal"`, `label2: "type:policy"` (from CSV)
* `guide.pdf` → `label1: "dept:support"`, `label2: "type:guide"` (from CSV)
* `terms.pdf` → `label1: "dept:general"`, `label2: "lang:en"` (defaults from request)

***

## Create Update Upload Link

```http
POST /knowledge/documents/update/upload-link
```

Generate a pre-signed URL to replace an existing document's content.

### Request Body

| Field              | Type   | Required | Description                                                           |
| ------------------ | ------ | -------- | --------------------------------------------------------------------- |
| `agentId`          | string | Yes      | Agent UUID                                                            |
| `environment`      | string | Yes      | `development`, `staging`, or `production`                             |
| `knowledgeBaseId`  | string | Yes      | Knowledge base UUID                                                   |
| `s3Key`            | string | \*       | Document path to update. Required if `customDocumentId` not provided. |
| `customDocumentId` | string | \*       | Your external document ID. Required if `s3Key` not provided.          |
| `fileName`         | string | Yes      | New file name                                                         |
| `label1`           | string | No       | Updated primary label in `namespace:value` format                     |
| `label2`           | string | No       | Updated secondary label in `namespace:value` format                   |
| `customMeta1`      | string | No       | Free-form custom metadata field 1 (max 500 chars)                     |
| `customMeta2`      | string | No       | Free-form custom metadata field 2 (max 500 chars)                     |
| `customMeta3`      | string | No       | Free-form custom metadata field 3 (max 500 chars)                     |
| `customMeta4`      | string | No       | Free-form custom metadata field 4 (max 500 chars)                     |

> **Note**: Provide either `s3Key` or `customDocumentId`, not both.

### Request Example

```json
{
  "agentId": "your-agent-id",
  "environment": "production",
  "knowledgeBaseId": "kb-abc123",
  "customDocumentId": "DOC-12345",
  "fileName": "refund-policy-v2.pdf",
  "label1": "dept:support",
  "label2": "lang:en",
  "customMeta1": "DOC-98765",
  "customMeta2": "John Smith"
}
```

### Response

```json
{
  "uploadId": "upload-uuid",
  "uploadUrl": "https://storage.example.com/...",
  "expiresIn": 3600,
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy-v2.pdf",
  "requiredHeaders": {
    "Content-Type": "application/pdf"
  }
}
```

***

## Complete Update Upload

```http
POST /knowledge/documents/update/upload-complete
```

Finalize document update and trigger reprocessing.

### Request Body

| Field      | Type   | Required | Description                                     |
| ---------- | ------ | -------- | ----------------------------------------------- |
| `uploadId` | string | Yes      | The `uploadId` from update/upload-link response |

### Request Example

```json
{
  "uploadId": "upload-uuid"
}
```

### Response

```json
{
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy-v2.pdf",
  "documentId": "document-uuid",
  "updatedAt": "2026-01-16T12:00:00.000Z",
  "status": "uploaded"
}
```

***

## Update Metadata

```http
PATCH /knowledge/documents/metadata
```

Update document labels and/or custom metadata without re-uploading the file.

### Request Body

| Field              | Type   | Required | Description                                                                      |
| ------------------ | ------ | -------- | -------------------------------------------------------------------------------- |
| `agentId`          | string | Yes      | Agent UUID                                                                       |
| `environment`      | string | Yes      | `development`, `staging`, or `production`                                        |
| `knowledgeBaseId`  | string | Yes      | Knowledge base UUID                                                              |
| `s3Key`            | string | \*       | Document path. Required if `customDocumentId` not provided.                      |
| `customDocumentId` | string | \*       | Your external document ID. Required if `s3Key` not provided.                     |
| `label1`           | string | No       | Updated primary label in `namespace:value` format                                |
| `label2`           | string | No       | Updated secondary label in `namespace:value` format                              |
| `customMeta1`      | string | No       | Updated free-form custom metadata field 1 (max 500 chars). Pass `null` to clear. |
| `customMeta2`      | string | No       | Updated free-form custom metadata field 2 (max 500 chars). Pass `null` to clear. |
| `customMeta3`      | string | No       | Updated free-form custom metadata field 3 (max 500 chars). Pass `null` to clear. |
| `customMeta4`      | string | No       | Updated free-form custom metadata field 4 (max 500 chars). Pass `null` to clear. |

### Request Example

```json
{
  "agentId": "your-agent-id",
  "environment": "production",
  "knowledgeBaseId": "kb-abc123",
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy.pdf",
  "label1": "dept:support",
  "label2": "status:reviewed",
  "customMeta1": "DOC-98765",
  "customMeta2": "John Smith"
}
```

### Response

```json
{
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy.pdf",
  "documentId": "document-uuid",
  "label1": "dept:support",
  "label2": "status:reviewed",
  "customMeta1": "DOC-98765",
  "customMeta2": "John Smith",
  "customMeta3": null,
  "customMeta4": null,
  "updatedAt": "2026-01-16T14:00:00.000Z"
}
```

***

## Get Document

```http
GET /knowledge/documents
```

Retrieve metadata for a specific document.

### Query Parameters

| Parameter          | Type   | Required | Description                                                  |
| ------------------ | ------ | -------- | ------------------------------------------------------------ |
| `agentId`          | string | Yes      | Agent UUID                                                   |
| `environment`      | string | Yes      | `development`, `staging`, or `production`                    |
| `knowledgeBaseId`  | string | Yes      | Knowledge base UUID                                          |
| `s3Key`            | string | \*       | Document path. Required if `customDocumentId` not provided.  |
| `customDocumentId` | string | \*       | Your external document ID. Required if `s3Key` not provided. |

### Request Example

```
GET /knowledge/documents?agentId=your-agent-id&environment=production&knowledgeBaseId=kb-abc123&customDocumentId=DOC-12345
```

### Response

```json
{
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy.pdf",
  "documentId": "document-uuid",
  "status": "ready",
  "contentType": "application/pdf",
  "fileSize": 204800,
  "label1": "dept:support",
  "label2": "lang:en",
  "customMeta1": "DOC-98765",
  "customMeta2": "John Smith",
  "customMeta3": null,
  "customMeta4": null,
  "createdAt": "2026-01-15T12:00:00.000Z",
  "updatedAt": "2026-01-16T14:00:00.000Z"
}
```

### Response Fields

| Field         | Type         | Description                                                                                   |
| ------------- | ------------ | --------------------------------------------------------------------------------------------- |
| `s3Key`       | string       | Document path; use for subsequent operations                                                  |
| `documentId`  | string       | Document UUID (your `customDocumentId` if provided during upload, otherwise system-generated) |
| `status`      | string       | Processing status (see [Status Values](#document-status-values))                              |
| `contentType` | string       | MIME type of the document (e.g., `application/pdf`)                                           |
| `fileSize`    | number       | File size in bytes                                                                            |
| `label1`      | string\|null | Primary label in `namespace:value` format                                                     |
| `label2`      | string\|null | Secondary label in `namespace:value` format                                                   |
| `customMeta1` | string\|null | Free-form custom metadata field 1                                                             |
| `customMeta2` | string\|null | Free-form custom metadata field 2                                                             |
| `customMeta3` | string\|null | Free-form custom metadata field 3                                                             |
| `customMeta4` | string\|null | Free-form custom metadata field 4                                                             |
| `createdAt`   | string       | ISO 8601 creation timestamp                                                                   |
| `updatedAt`   | string       | ISO 8601 last update timestamp                                                                |

***

## Delete Document

```http
DELETE /knowledge/documents
```

Remove a document from the knowledge base.

### Request Body

| Field              | Type   | Required | Description                                                  |
| ------------------ | ------ | -------- | ------------------------------------------------------------ |
| `agentId`          | string | Yes      | Agent UUID                                                   |
| `environment`      | string | Yes      | `development`, `staging`, or `production`                    |
| `knowledgeBaseId`  | string | Yes      | Knowledge base UUID                                          |
| `s3Key`            | string | \*       | Document path. Required if `customDocumentId` not provided.  |
| `customDocumentId` | string | \*       | Your external document ID. Required if `s3Key` not provided. |

### Request Example

```json
{
  "agentId": "your-agent-id",
  "environment": "production",
  "knowledgeBaseId": "kb-abc123",
  "customDocumentId": "DOC-12345"
}
```

### Response

```json
{
  "success": true,
  "s3Key": "agents/<agentId>/production/<kbId>/refund-policy.pdf",
  "documentId": "document-uuid"
}
```
