# 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](/platform/knowledge-bases.md). 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](/sdk/knowledge-base-rag.md)).

***

## 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"
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.minded.com/api/knowledge.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
