> Source: https://builder.ema.ai/v2/api-reference/knowledge-ingestion-api
> Title: Knowledge & Ingestion API

# Knowledge & Ingestion API

A knowledge base (KB) is the grounding an AI Employee searches at run time. The Knowledge & Ingestion API is where you build that grounding: register a connection to an external source, create a KB under an AI Employee, upload or sync documents into it, and organize those documents with taxonomies and tags. The ingestion service is mounted at `/api/v1/ingestion`, so every path below is that prefix plus the path shown.

All requests require a [JWT or tenant API key](/builder/v2/api-reference/authentication). Examples use `https://your-tenant.ema.co` as the host.

> [INFO]
> **Knowledge bases belong to an AI Employee.** Every KB is scoped to an AI Employee, so most paths begin with `/ai-employees/{ai_employee_id}/knowledge-bases`. The `ai_employee_id` is the same UUID as the workflow that powers the AI Employee. A request that names an AI Employee you are not a member of returns `403`.

## Connections

A connection holds the credentials for one external source — SharePoint, Google Drive, Confluence, Box, ServiceNow, or the platform's own local-file store. You create a connection once, then bind one or more knowledge bases to it.

-   **List:** `GET /api/v1/ingestion/connections`.
-   **Create:** `POST /api/v1/ingestion/connections`.
-   **Get / update / delete:** `GET`, `PUT`, `DELETE /api/v1/ingestion/connections/{id}`.

```http
POST https://your-tenant.ema.co/api/v1/ingestion/connections
Authorization: Bearer eyJhbGciOiJSUzI1Ni...
Content-Type: application/json

{
  "name": "Engineering Confluence",
  "description": "Shared engineering spaces",
  "connector_type": "confluence",
  "connector_config": "{\"base_url\":\"https://acme.atlassian.net\",\"api_token\":\"...\"}"
}
```

`connector_type` is one of `local_file`, `sharepoint`, `google_drive`, `confluence`, `box`, `the-dot`, or `servicenow`. `connector_config` is a raw JSON string carrying the connector's credentials. The response is the created `Connection` with its `id`, `status`, and `created_at`.

> [TIP]
> **OAuth2 connectors.** Confluence, Box, SharePoint, and Google Drive support an OAuth2 authorization flow at `GET /api/v1/ingestion/connections/{connector}/oauth2/authorize`, with the provider redirecting back to the matching `/oauth2/callback`. Check availability first with `GET /api/v1/ingestion/connections/{connector}/oauth2/available`. The callback routes are public (the provider, not your credential, calls them).

## Knowledge bases

A knowledge base groups documents under one AI Employee. A KB can be backed by a connection (synced from an external source) or be a local-file KB with no backing connection.

-   **List:** `GET /api/v1/ingestion/ai-employees/{ai_employee_id}/knowledge-bases`.
-   **Create:** `POST /api/v1/ingestion/ai-employees/{ai_employee_id}/knowledge-bases`.
-   **Get / update / delete:** `GET`, `PUT`, `DELETE /api/v1/ingestion/ai-employees/{ai_employee_id}/knowledge-bases/{id}`.

```http
POST https://your-tenant.ema.co/api/v1/ingestion/ai-employees/3f7a.../knowledge-bases
Authorization: Bearer eyJhbGciOiJSUzI1Ni...
Content-Type: application/json

{
  "name": "Support runbooks",
  "description": "Internal runbooks for tier-1 support",
  "connection_id": "8c4d...",
  "intent": "search"
}
```

Omit `connection_id` (or send `null`) to create a local-file KB. `intent` selects the ingestion pipeline:

-   `search` (default) — chunks and embeds documents for retrieval. This is the right choice for a KB an AI Employee searches.
-   `extraction` — masks the full extracted markdown once and skips chunking, embedding, and auto-tagging. Use it for workflow file uploads that an LLM consumes directly rather than searching.

For a Confluence connection, include `connector_options` with at least one `space_keys` entry or `root_page_ids` entry to scope the sync.

The `KnowledgeBase` response carries a `document_counts` object (`processed`, `failed`, `processing`, `pending`, `last_sync_failed`), an `orphaned` flag (true if the backing connection was deleted), and `last_synced_at`.

## Documents

Documents live inside a KB. You upload them directly, or let a sync pull them from the connection.

-   **List:** `GET /api/v1/ingestion/ai-employees/{ai_employee_id}/knowledge-bases/{id}/documents` — paginated, with optional filters:
    
    -   `search` — case-insensitive substring match on the document title.
    -   `status` — `pending`, `processing`, `processed`, `failed`, or `deleted`.
    -   `folder_path` — exact-match folder filter (e.g. `/ENG/Getting Started/`).
    -   `tag_node_id` — repeatable; AND semantics, so the document must carry every named tag.
    -   `sync_log_id` — restrict to the documents touched by one sync run.
    
    The response is a flat array of `Document` objects; the total count, page, and page size come back in the `X-Total-Count`, `X-Page`, and `X-Page-Size` response headers.
-   **Folder tree:** `GET .../knowledge-bases/{id}/folder-tree` returns the full folder hierarchy (paths and counts only, never paginated).
-   **Folder children:** `GET .../knowledge-bases/{id}/folder-children?path=/` returns the paginated direct folders and files at a path.
-   **Get / delete a document:** `GET`, `DELETE /api/v1/ingestion/documents/{id}`.
-   **Download:** `GET /api/v1/ingestion/documents/{id}/file` returns the original file bytes; `GET /api/v1/ingestion/documents/{id}/image` returns a rendered image where vision ingestion produced one.
-   **Retry a failure:** `POST .../knowledge-bases/{id}/documents/{document_id}/retry` resets a failed but retriable document to `pending`.

### Upload a file

`POST /api/v1/ingestion/ai-employees/{ai_employee_id}/knowledge-bases/{id}/upload` takes a `multipart/form-data` body with a single `file` part.

```http
POST https://your-tenant.ema.co/api/v1/ingestion/ai-employees/3f7a.../knowledge-bases/9b2c.../upload
Authorization: Bearer eyJhbGciOiJSUzI1Ni...
Content-Type: multipart/form-data; boundary=----boundary

------boundary
Content-Disposition: form-data; name="file"; filename="runbook.pdf"
Content-Type: application/pdf

<binary file bytes>
------boundary--
```

The response is `201 Created` with the new document's ID, chunk count, and status:

```json
{
  "document_id": "a1b2...",
  "chunk_count": 42,
  "status": "active",
  "message": "File uploaded and processed"
}
```

To upload many files under one sync log, start a batch with `POST .../knowledge-bases/{id}/upload-batch` (returns a `batch_id`), upload each file, then close it with `POST .../knowledge-bases/{id}/upload-batch/{batchId}/complete`.

## Sync

For KBs backed by an external connector, sync pulls files from the source, diffs them against what is already stored, and enqueues new or changed documents.

-   **Trigger now:** `POST /api/v1/ingestion/ai-employees/{ai_employee_id}/knowledge-bases/{id}/sync`. Only works for connector-backed KBs (not `local_file`); a sync already in progress returns `409`.
-   **Sync config:** `POST`, `GET`, `PUT`, `DELETE .../knowledge-bases/{id}/sync-config`. The config sets `schedule_type` (`interval` or `manual`) and, for interval schedules, `interval_minutes`.
-   **Sync logs:** `GET .../knowledge-bases/{id}/sync-logs` lists past sync runs; `GET /api/v1/ingestion/sync-logs/{id}` fetches one.

## Taxonomies and tags

A taxonomy is a tree of tag nodes you define per AI Employee, then apply to documents to organize and filter them.

-   **Taxonomies:** `GET`, `POST /api/v1/ingestion/ai-employees/{ai_employee_id}/taxonomies`, plus `GET`, `PUT`, `DELETE .../taxonomies/{taxonomy_id}`.
-   **Nodes:** `GET`, `POST .../taxonomies/{taxonomy_id}/nodes`; rename with `PUT` and remove a node and its descendants with `DELETE .../taxonomies/{taxonomy_id}/nodes/{node_id}`.
-   **Tag a document:** `POST .../knowledge-bases/{id}/documents/{doc_id}/tags` stores the chosen node and all of its ancestors. List a document's tags with the matching `GET`, and remove a single tag with `DELETE .../tags/{node_id}`.

### Auto-tagging

`POST /api/v1/ingestion/ai-employees/{ai_employee_id}/taxonomies/{taxonomy_id}/auto-tag` runs LLM-based tagging across the documents in the knowledge bases you name. To make a taxonomy the default for a KB's new documents, set it with `PUT .../knowledge-bases/{id}/auto-tag-config` (and read the current setting with the matching `GET`).

## What's next

-   [AI Employee API](/builder/v2/api-reference/ai-employee-api) — create the AI Employee that owns these knowledge bases.
-   [Integrations API](/builder/v2/api-reference/integrations-api) — manage connections and Tools as installed integrations.
-   [Workflow API](/builder/v2/api-reference/workflow-api) — run the workflow that searches these knowledge bases.
