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. Examples use https://your-tenant.ema.co as the host.
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}.
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.
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}.
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, ordeleted.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.
Documentobjects; the total count, page, and page size come back in theX-Total-Count,X-Page, andX-Page-Sizeresponse headers. - Folder tree:
GET .../knowledge-bases/{id}/folder-treereturns 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}/filereturns the original file bytes;GET /api/v1/ingestion/documents/{id}/imagereturns a rendered image where vision ingestion produced one. - Retry a failure:
POST .../knowledge-bases/{id}/documents/{document_id}/retryresets a failed but retriable document topending.
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.
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:
{
"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 (notlocal_file); a sync already in progress returns409. - Sync config:
POST,GET,PUT,DELETE .../knowledge-bases/{id}/sync-config. The config setsschedule_type(intervalormanual) and, for interval schedules,interval_minutes. - Sync logs:
GET .../knowledge-bases/{id}/sync-logslists 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, plusGET,PUT,DELETE .../taxonomies/{taxonomy_id}. - Nodes:
GET,POST .../taxonomies/{taxonomy_id}/nodes; rename withPUTand remove a node and its descendants withDELETE .../taxonomies/{taxonomy_id}/nodes/{node_id}. - Tag a document:
POST .../knowledge-bases/{id}/documents/{doc_id}/tagsstores the chosen node and all of its ancestors. List a document's tags with the matchingGET, and remove a single tag withDELETE .../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 — create the AI Employee that owns these knowledge bases.
- Integrations API — manage connections and Tools as installed integrations.
- Workflow API — run the workflow that searches these knowledge bases.