REST API
All endpoints are under the /api prefix. Document processing runs asynchronously: digitization, rewriting, and embedding are background jobs. Upload or update a document, then poll document and knowledge-base status.
Authentication
Supply your API key in the X-API-Key header.
curl -X GET https://knowledge.hidoba.com/api/knowledgebases/my-partner \
-H "X-API-Key: YOUR_API_KEY"
Most endpoints allow either an administrator key or a key scoped to {partner}.
Endpoints explicitly marked admin only require an administrator key.
Knowledge-base Budgets
Every KB can have optional limits for accepted digitized characters, lifetime model tokens, and lifetime customer charges. These limits apply to file uploads, URLs, batch and manual processing, retries, fallbacks, embeddings, individual YouTube videos, and YouTube channel discovery.
| API field | Type | What it limits |
|---|---|---|
character_limit | Integer | Accepted digitized characters for non-deleted documents. |
token_limit | Integer | Lifetime recorded rewrite and embedding input plus output tokens. |
dollar_limit_usd | Decimal string or number | Lifetime recorded customer charges, to 8 decimal places. |
For persisted KB limits, null means unlimited and 0 blocks further
consumption. Existing request-level character_limit fields are positive
integers. When both kinds of character limit are present, the smaller value
applies. Deleting content releases character capacity only; it never refunds
lifetime tokens or charges.
Before a bounded paid operation starts, the service checks current consumption and outstanding reservations under a KB database lock. It reserves a verified operation bound before dispatch, records actual usage after completion, and releases unused verified capacity. Missing usage or an ambiguous provider outcome blocks capped work instead of allowing an unverified request.
Budget-blocked work is retained durably. The document remains visible with a
BUDGET_BLOCKED: processing error and resumes automatically after a relevant
limit increases or character capacity is freed. Cached extracted text is kept for
resumption so the provider is not called again.
Content Types
List Content Types
GET /api/content_types
Returns the available content types for rewriting. No authentication required.
Response
{
"content_types": [
{ "id": "auto", "name": "Auto (detect from source)" },
{ "id": "article", "name": "Article" },
{ "id": "youtube", "name": "YouTube" },
{ "id": "book", "name": "Book" }
]
}
Knowledge Bases
List Knowledge Bases
GET /api/knowledgebases/{partner}
Returns all knowledge bases for the partner, including aggregate embedding status and lifetime processing-ledger totals used by the Knowledge UI.
Response
[
{
"name": "my-kb",
"embedding_status": "success",
"expert_name": "Ada Lovelace",
"lifetime_usage": {
"event_count": 47,
"priced_event_count": 45,
"unpriced_event_count": 2,
"cost_usd_total": 0.9675,
"rewrite_event_count": 35,
"digitization_event_count": 12
},
"rewrite_usage": [
{
"model": null,
"rewritten_count": 35,
"rejected_count": 0,
"complete_usage_count": 36,
"complete_cost_count": 35,
"cost_usd_total": 0.78,
"input_tokens_total": 1200000,
"output_tokens_total": 450000,
"fallback_complete_usage_count": 0,
"fallback_input_tokens_total": 0,
"fallback_output_tokens_total": 0
}
],
"digitization_usage": {
"apify_document_count": 12,
"complete_cost_count": 12,
"cost_usd_total": 0.1875
},
"deletion_requested_at": null
}
]
embedding_status is one of success, in_progress, fail, none, or delete_pending.
lifetime_usage is the authoritative aggregate for all settled usage events in
the KB. It includes discovery, digitization, rewriting, embeddings, retries, and
other priced work recorded by the service. priced_event_count and
unpriced_event_count make incomplete historical pricing visible.
rewrite_usage and digitization_usage are retained for compatibility with
older clients. They are derived from the same lifetime ledger: their model
field is currently null, rewritten_count represents settled rewrite events,
and apify_document_count represents settled digitization events. Use
lifetime_usage and the KB Budget Status endpoint for
current accounting and admission state. The document-level spend display remains
useful for the most recent document attempt; see Spend in the Web UI.
Create Knowledge Base
POST /api/knowledgebases/{partner}
Content-Type: multipart/form-data
curl -X POST https://knowledge.hidoba.com/api/knowledgebases/my-partner \
-H "X-API-Key: YOUR_API_KEY" \
-F "name=my-kb"
| Parameter | Type | Default | Description |
|---|---|---|---|
name | String | — | Knowledge base name. Required. |
character_limit | Integer | — | Optional non-negative stored digitized-character limit. |
token_limit | Integer | — | Optional non-negative lifetime model-token limit. |
dollar_limit_usd | Decimal | — | Optional non-negative lifetime customer-charge limit, with up to 8 decimal places. |
expert_name | String | — | Knowledge base-level expert/author metadata. |
user_email | String | — | Knowledge base-level user email metadata. |
Get KB Budget Status
GET /api/knowledgebases/{partner}/{kb}/limits
Returns configured limits, settled consumption, outstanding reservations, remaining capacity, unknown usage counts, and reasons processing is paused.
{
"limits": {
"character_limit": 1000000,
"token_limit": 5000000,
"dollar_limit_usd": 10.0
},
"characters": { "limit": 1000000, "consumed": 125000, "reserved": 0, "remaining": 875000, "unknown_events": 0 },
"tokens": { "limit": 5000000, "consumed": 480000, "reserved": 1114112, "remaining": 3405888, "unknown_events": 0 },
"dollars": { "limit": 10.0, "consumed": 1.42, "reserved": 0.5, "remaining": 8.08, "unknown_events": 0 },
"uncertain_operations": 0,
"blocking_reasons": [],
"blocked": false
}
remaining is clamped to zero. Check blocking_reasons to distinguish an
exhausted limit, unknown historical usage, and an unresolved provider outcome.
Outstanding reservations are included in token and USD admission.
Update KB Budgets
PATCH /api/knowledgebases/{partner}/{kb}/limits
Content-Type: application/json
curl -X PATCH https://knowledge.hidoba.com/api/knowledgebases/my-partner/my-kb/limits \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"character_limit": 1000000,
"token_limit": 5000000,
"dollar_limit_usd": "10.00000000"
}'
Omit a property to preserve it. Send an explicit null to remove its limit.
The response has the same shape as GET. Raising a limit wakes eligible pending
work. Lowering one below historical usage is accepted and immediately blocks new
spending; it cannot cancel or refund an already-dispatched operation.
Delete Knowledge Base
DELETE /api/knowledgebases/{partner}/{kb}
Deletes the knowledge base immediately when possible. If documents, vector
cleanup, or provider-usage settlement are still active, the response status is
delete_pending and includes pending cleanup details.
Folders
List Folders
GET /api/folders/{partner}/{kb}
Response
{
"folders": ["chapter-1", "chapter-2"]
}
Create Folder
POST /api/folders/{partner}/{kb}
Content-Type: multipart/form-data
curl -X POST https://knowledge.hidoba.com/api/folders/my-partner/my-kb \
-H "X-API-Key: YOUR_API_KEY" \
-F "name=chapter-1"
| Form field | Type | Default | Description |
|---|---|---|---|
name | String | — | Folder name. Required. |
type | String | regular | regular or youtube_channel. |
channel_url | String | — | Required for youtube_channel: an @handle, /channel/UC…, /user/…, or /c/… YouTube channel URL. |
model_tier | String | standard | standard or economy for future channel-video work. |
For a regular folder, send only name or leave type=regular. For a channel
folder, create the ordinary folder and durable channel source in one request:
curl -X POST https://knowledge.hidoba.com/api/folders/my-partner/my-kb \
-H "X-API-Key: YOUR_API_KEY" \
-F "name=Hidoba videos" \
-F "type=youtube_channel" \
-F "channel_url=@HidobaAI" \
-F "model_tier=economy"
The initial scan is scheduled immediately. It only starts when the KB has
budget headroom; otherwise the source is created in budget_blocked state.
The normal folder-list endpoint remains backward compatible and returns names
only. Use Get Combined Data for channel source details.
Update Channel Settings
PATCH /api/folders/{partner}/{kb}/{folder}/channel
Content-Type: application/json
{
"enabled": false,
"model_tier": "economy"
}
Both fields are optional. enabled pauses or resumes future scans; setting
model_tier changes future imported-video processing. The channel URL and
canonical identity cannot be changed. A duplicate alias source returns 409
while the source that owns that channel still exists.
Run a Channel Sync Now
POST /api/folders/{partner}/{kb}/{folder}/sync
Returns { "status": "pending", "budget": { ... } }. Resume a paused
source before requesting a sync. A sync run is subject to the current KB budget
and may move to budget_blocked without starting paid discovery.
Delete Folder
DELETE /api/folders/{partner}/{kb}/{folder}
Deletes the folder immediately when possible. If documents or vector cleanup are
still active, the response status is delete_pending. Deleting a channel folder
disables discovery before cleanup. Explicitly deleted channel videos remain
suppressed while their channel source is retained.
Documents
List Documents
GET /api/documents/{partner}/{kb}
Returns the knowledge base with all documents and aggregate embedding info.
Get Combined Data
GET /api/kb-data/{partner}/{kb}
Returns documents, folders, pending folder deletions, aggregate embedding info,
the current budget status, and folder_details for channel sources in one call.
It also includes usage_totals, legacy request-level quota_info, an optional
public openai_sync summary, and deletion_requested_at. folders remains the
legacy list of folder names.
Each folder_details entry describes a YouTube channel source:
| Field | Description |
|---|---|
id, name, type | Durable source ID, folder name, and youtube_channel. |
channel_url, channel_id | Submitted channel alias and resolved canonical channel ID when available. |
enabled, model_tier, status, last_error | Current sync controls and state. Status may be pending, syncing, synced, incomplete, budget_blocked, paused, error, or duplicate. |
last_sync_at, next_sync_at | Last complete scan and next scheduled check. |
counts | Video counts by pending, deferred, imported, duplicate, or suppressed status. |
duplicate_source, duplicate_document_ids | Link to an existing channel source and up to 100 documents already present elsewhere in the KB. |
Channel scans include regular videos, Shorts, and completed livestreams. Active
or upcoming streams are deferred; newly imported videos are sent through the
ordinary URL pipeline newest first. Complete metadata scans run every 24 hours.
Get KB Statistics
GET /api/kb-stats/{partner}/{kb}
Response
{
"document_count": 42,
"digitized_count": 40,
"draft_rewrite_count": 38,
"final_rewrite_count": 35,
"total_digitized_chars": 250000,
"total_draft_rewrite_chars": 200000,
"total_final_rewrite_chars": 180000,
"error_count": 2,
"embedded_count": 35
}
Get Single Document
GET /api/document/{partner}/{kb}/{doc_id}
Create Document (File Upload)
POST /api/documents/{partner}/{kb}
Content-Type: multipart/form-data
curl -X POST https://knowledge.hidoba.com/api/documents/my-partner/my-kb \
-H "X-API-Key: YOUR_API_KEY" \
-F "type=file" \
-F "folder=chapter-1" \
-F "[email protected]" \
-F "auto_rewrite=true" \
-F "character_limit=250000" \
-F "model_tier=standard"
Form Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
type | String | — | file or url. Required. |
folder | String | — | Target folder name. Required. |
file | File | — | File to upload. Required when type=file. |
url | String | — | URL to fetch. Required when type=url. |
name | String | — | Document name. Auto-detected from file/URL if omitted. |
expert_name | String | — | Content author or speaker name. |
user_email | String | — | Email of the uploading user. |
auto_rewrite | String | false | Automatically queue for rewriting after digitization. Pass "true" to enable. |
model_tier | String | standard | LLM model tier: standard or economy. |
use_original_as_rewritten | String | false | Skip LLM rewriting and use the original/digitized content as final rewritten content. Pass "true" to enable. |
character_limit | Integer | — | Optional positive request-level total digitized-character cap. The smaller of this and a stored KB character limit applies when content is committed. |
When final rewritten content is created, embedding is queued automatically. This happens only after digitized content has passed any supplied character limit, then after a successful rewrite, after use_original_as_rewritten=true, or after uploading/updating rewritten content.
Uploads are validated by file extension and file signature. Supported extensions are PDF, DOC/DOCX, PPT/PPTX, XLS/XLSX, EPUB, MD/MARKDOWN, HTML/HTM, TXT/PY/JS/CSS, CSV/JSON/XML/YAML/YML, MP4/MOV/M4V/AVI, MP3/WAV/M4A, and JPG/JPEG/PNG/TIF/TIFF/GIF/WebP. Archives such as ZIP, TAR, GZ/TGZ, RAR, 7Z, BZ2, and XZ are blocked.
Create Document (URL)
curl -X POST https://knowledge.hidoba.com/api/documents/my-partner/my-kb \
-H "X-API-Key: YOUR_API_KEY" \
-F "type=url" \
-F "folder=articles" \
-F "url=https://example.com/article"
Batch URL Import
POST /api/documents/{partner}/{kb}/batch
Content-Type: application/json
curl -X POST https://knowledge.hidoba.com/api/documents/my-partner/my-kb/batch \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"folder": "articles",
"urls": [
"https://example.com/article-1",
"https://example.com/article-2"
],
"use_original_as_rewritten": false
}'
Maximum 1,000 URLs per batch request.
If use_original_as_rewritten is true, each URL is still digitized first, then the digitized content is saved as final rewritten content and embedded automatically.
The JSON request also accepts auto_rewrite (boolean, default false),
model_tier (standard or economy), expert_name, user_email, and an
optional positive request-level character_limit.
Response
{
"summary": {
"total": 2,
"succeeded": 2,
"failed": 0
},
"results": [
{
"url": "https://example.com/article-1",
"status": "success",
"document_id": "a1b2c3d4-e5f6-..."
},
{
"url": "https://example.com/article-2",
"status": "success",
"document_id": "f7g8h9i0-j1k2-..."
}
]
}
Batch File Upload
POST /api/documents/{partner}/{kb}/files/batch
Content-Type: multipart/form-data
Send one or more files, a required folder, and optional names entries in
the same order as files. The endpoint also accepts use_original_as_rewritten,
auto_rewrite, character_limit, model_tier, expert_name, and user_email
with the same meanings as a single upload. It returns a per-file result and a
summary with total, succeeded, and failed counts.
The request supports at most the configured batch file count and combined size. Each accepted file follows the same budget admission path as a single upload; one blocked or invalid file does not roll back unrelated files in the batch.
Create Empty Document
POST /api/documents/{partner}/{kb}/empty
Content-Type: multipart/form-data
Creates a document with no content, for manual content editing.
| Parameter | Type | Default | Description |
|---|---|---|---|
name | String | — | Document name. Required. |
folder | String | — | Target folder name. Required. |
type | String | — | file or url. Required. |
url | String | — | URL (if type is url). |
Rename Document
PUT /api/documents/{partner}/{kb}/{doc_id}/name
Send name as a form parameter.
Update Document Type
PUT /api/documents/{partner}/{kb}/{doc_id}/type
Send type as a form parameter. Valid values are file and url.
Update Document URL
PUT /api/documents/{partner}/{kb}/{doc_id}/url
Send url as a form parameter.
Delete Document
DELETE /api/documents/{partner}/{kb}/{doc_id}
Deletion is allowed by default even if a document is being processed. If active work or vector cleanup still blocks final deletion, the response status is delete_pending and includes pending queue/vector cleanup details. Pass force=false to return 409 instead when active processing would block deletion.
curl -X DELETE "https://knowledge.hidoba.com/api/documents/my-partner/my-kb/DOC_ID?force=false" \
-H "X-API-Key: YOUR_API_KEY"
Document Content
Get Content
GET /api/documents/{partner}/{kb}/{doc_id}/content/{type}
Where {type} is one of: original, digitized, rewritten, draft.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
format | string | raw | markdown returns rewritten/draft content rendered as clean markdown — the same rendered version shown in the dashboard's rewritten document view. Ignored for original/digitized. |
Response
{
"content": "# Document Title\n\nProcessed document content...",
"format": "raw"
}
format in the response reflects what was actually returned: "markdown" when rendered markdown was returned, otherwise "raw".
Without format=markdown, rewritten/draft content is returned as the document's raw stored content, which is not guaranteed to be clean, readable markdown. Use format=markdown to reliably fetch the fully rendered markdown version.
Returns 400 if format is not raw or markdown, or if format=markdown is requested for a rewritten/draft document that hasn't been successfully rewritten yet.
Update Content
PUT /api/documents/{partner}/{kb}/{doc_id}/content/{type}
Send content as a form parameter. For updates, {type} is one of: original, digitized, rewritten.
For type=digitized, you can also send an optional positive request-level
character_limit form parameter. It is combined with the stored KB character
limit using the smaller value. A request-level-only rejection returns 403 with
detail set to QUOTA_EXCEEDED:knowledge_chars; the previous digitized content
remains in place. A persisted KB budget block returns a budget_blocked status
and retains the content as pending work. The parameter has no quota effect for
original or rewritten updates.
When {type} is rewritten, existing vectors for that document are cleaned up and a fresh embedding job is queued automatically.
Upload Content as File
POST /api/documents/{partner}/{kb}/{doc_id}/content/{type}
Content-Type: multipart/form-data
For uploads, {type} is one of: original, digitized, rewritten.
Upload the content in the file multipart field.
For type=digitized, you can also send an optional positive request-level
character_limit form parameter. The uploaded digitized file must be UTF-8.
The smaller of that limit and a stored KB character limit applies. A
request-level-only rejection returns 403 with detail set to
QUOTA_EXCEEDED:knowledge_chars; a persisted KB budget block returns
{ "status": "budget_blocked", "filename": "…" }. Both preserve the
previous accepted content.
When {type} is rewritten, existing vectors for that document are cleaned up and a fresh embedding job is queued automatically.
Download Document File
GET /api/documents/{partner}/{kb}/{doc_id}/download/{type}
Where {type} is one of: original, digitized, rewritten, draft.
Download Rewritten Bundle
GET /api/documents/{partner}/{kb}/rewritten-bundle
Returns a ZIP archive of all rewritten documents in the knowledge base. The archive contains documents_info.json and one {doc_id}.md file per rewritten document.
Processing
Queue Document for Processing
POST /api/queue/process
| Parameter | Type | Default | Description |
|---|---|---|---|
document | Object | — | Document object (JSON body). |
action | String | digitize | Processing action: digitize or rewrite. |
partner | String | — | Partner name. |
kb | String | — | Knowledge base name. |
content_type | String | auto | auto, article, youtube, or book. |
person_name | String | — | Author/speaker name for the rewrite prompt. |
character_limit | Integer | — | Optional positive request-level digitized-character cap. Used when action=digitize; the smaller stored KB limit still applies. |
Send document in the JSON body. Send action, partner, kb, content_type, person_name, and optional character_limit as query parameters.
Rewriting produces final rewritten content. When that content is saved, embedding
is queued automatically. For action=digitize, rewrite/embedding work begins
only after digitized content passes any applicable character limit. This endpoint,
the two bulk rewrite endpoints, and automatic queues all use the same budget
admission controls. A paused document remains visible and resumes when capacity
becomes available; clients should inspect the KB budget endpoint and document
processing_error instead of retrying a blocked request in a loop.
Content Type Auto-Detection
When content_type is set to auto:
- YouTube URLs and audio files →
youtubetemplate - PDF, EPUB, and Word documents →
booktemplate - Everything else →
articletemplate
Bulk Rewrite (Folder)
POST /api/bulk/rewrite/folder/{partner}/{kb}/{folder}
| Parameter | Type | Default | Description |
|---|---|---|---|
skip_rewritten | Boolean | true | Skip documents that already have rewritten content. |
content_type | String | auto | Content type template to use. |
person_name | String | — | Author/speaker name. |
These options are query parameters.
Bulk Rewrite (Knowledge Base)
POST /api/bulk/rewrite/kb/{partner}/{kb}
| Parameter | Type | Default | Description |
|---|---|---|---|
skip_rewritten | Boolean | true | Skip documents that already have rewritten content. |
content_type | String | auto | Content type template to use. |
person_name | String | — | Author/speaker name. |
These options are query parameters.
Embedding
Embedding is automatic after final rewritten content is saved. Retry and manual queue endpoints are also available when operational recovery is needed.
The embedding worker indexes final rewritten content only. A document becomes eligible for embedding when file_rewritten is set. Use the document fields and aggregate KB status below to monitor progress.
Get Embedding Status
GET /api/embedding/{partner}/{kb}
Returns aggregate embedding status for the knowledge base. This is a read/status endpoint; it does not start embedding.
Response
{
"last_successful_update_time": "2025-01-15T10:30:00Z",
"last_update_time": "2025-01-15T10:30:00Z",
"last_update_status": "success",
"last_update_details": {
"chunk_count": 35,
"point_count": 35
},
"last_successful_details": {
"chunk_count": 35,
"point_count": 35
},
"knowledge_base_id": "42",
"embedding_profile_id": 1,
"embedding_profile_name": "default",
"eligible_document_count": 35,
"pending_document_count": 0,
"failed_document_count": 0,
"embedded_document_count": 35,
"last_error": null
}
last_update_status is in_progress, success, fail, or null. Per-document embedding state is available on document objects.
Retry Failed Embeddings
POST /api/embedding/{partner}/{kb}/retry-failed
Requeues failed embedding jobs for the KB and returns the number queued plus the
updated embedding_info. Budget admission still applies before each paid
embedding provider request.
Queue One Document for Embedding
POST /api/embedding/{partner}/{kb}/documents/{doc_id}?force=true
Queues one rewritten document. force defaults to true. The endpoint returns
the job ID, current document, and aggregate embedding status. It rejects a
document with no final rewritten content or one still in digitize/rewrite work.
OpenAI Vector Store Sync
These admin-only endpoints operate only when OpenAI sync is enabled for the partner:
| Endpoint | Description |
|---|---|
GET /api/openai-sync/{partner}/{kb} | Read KB vector-store and document sync status. |
POST /api/openai-sync/{partner}/{kb}/backfill | Queue all rewritten documents for sync. |
POST /api/openai-sync/{partner}/{kb}/retry-failed | Queue only failed sync documents. |
Backfill and retry return { "status": "queued", "queued": <count> } and
return 409 if sync is disabled or the KB is pending deletion.
Table of Contents
GET /api/toc/{partner}/{kb}?include_status=false
Returns the current table of contents projected from embedding manifests. Set
include_status=true to include embedding-status details with the hierarchy.
RAG Retrieval Diagnostics
POST /api/rag-test/search
Content-Type: application/json
Run hybrid retrieval diagnostics against the KB's current embedding profile and
index. The caller must have access to the partner in the request body.
{
"partner": "my-partner",
"kb": "my-kb",
"user_message": "What does the handbook say about leave?",
"robot_message": "",
"character_replacement_name": "Ada"
}
user_message is required and both message fields allow up to 20,000
characters. The optional robot_message is combined with the user message for
retrieval. The endpoint returns the effective configuration, per-retriever
streams, fused combined_results, supported BM25 languages, timings, and the
total result count.
The default retrieval settings are top_k=12, search_multiplier=6, and
rrf_k=15. You may also provide rrf_weight_dense, rrf_weight_sparse,
rrf_weight_bm25, query_weight_original, and query_weight_replaced to tune
fusion. Non-admin callers must use the default top_k, search_multiplier,
and rrf_k; collection_override and rag_index_override are admin-only.
Non-admin responses omit internal routing and identifier fields.
Administration and Diagnostics
| Endpoint | Access | Description |
|---|---|---|
GET /api/auth/me | Any authenticated key | Returns the current key's partner scope and isAdmin flag. |
GET /api/partners | Any authenticated key | Lists all partners for admins, or only the caller's partner for scoped keys. |
GET, POST, PUT, DELETE /api/partners/{partner} | Admin only | Read, create, update, or delete a partner. Partner creation returns the generated API key once. |
POST /api/partners/{partner}/regenerate-key | Admin only | Replaces the partner key and returns the new key once. |
GET /api/prompts/{content_type} | Admin only | Returns the configured rewrite prompt. auto resolves to article. |
GET /api/queue | Admin only | Returns combined queue status. |
GET /api/queue/jobs?limit=100 | Admin only | Returns combined jobs; limit is 1–1000. |
GET /api/queue/debug | Admin only | Correlates durable queue markers and BullMQ jobs. |
POST /api/queue/retry-failed | Admin only | Retries failed rewrite queue jobs. |
DELETE /api/queue/clear-orphans | Admin only | Clears unrepresented non-durable queue markers after a verified scan. |
Partner create and update requests use multipart/form-data. Creation accepts
max_documents (default 100000000), allow_audio_video (default true),
and openai_sync_enabled (default false). Update accepts those same optional
fields plus new_name; enabling OpenAI sync queues existing eligible documents.
Partner deletion returns 409 while vector state, OpenAI sync cleanup, or an
unsettled budget reservation remains. A partner rename is also rejected while
embedding or OpenAI state would make the remote identity unsafe to change.
Document Model
A document returned from the API includes the following fields:
| Field | Type | Description |
|---|---|---|
id | String | UUID identifier. |
name | String | Document name. |
folder | String | Folder name. |
type | String | file or url. |
url | String | Source URL (if type is url). |
file_original | String | Original uploaded filename. |
file_digitized | String | Digitized content filename. |
file_rewritten_draft | String | Draft rewrite filename. |
file_rewritten | String | Final rewrite filename. |
user_email | String | Email of the uploading user. |
in_queues | Array | Active processing queues (e.g., ["digitize"], ["rewrite"], ["embedding"]). |
expert_name | String | Content author/speaker. |
auto_rewrite | Boolean | Whether auto-rewrite is enabled. |
model_tier | String | standard or economy. |
digitization_provider | String | Provider for the latest successful digitization when billing metadata was captured. Currently populated for Apify routes; null for other and legacy digitizations. |
digitization_cost_usd | Number | This document's allocated share of the successful Apify Actor run's actual usageTotalUsd; null when unavailable or not applicable. |
rewrite_model | String | LLM model used for rewriting. |
input_file_tokens | Integer | Estimated source tokens for the rewritten input. For LLM rewrites, this is derived from first-pass provider prompt usage minus prompt overhead; split inputs follow the actual chunk prompts, including overlap. For content accepted as rewritten without an LLM rewrite, such as use_original_as_rewritten, this is calculated locally from the original or digitized text stored as rewritten. Null for pre-3.0.2 rewrite stats until the document is rewritten again or backfilled. |
rewrite_input_tokens_total | Integer | Provider-reported prompt tokens across all calls in the latest rewrite attempt, including generated output later rejected by validation. Null for pre-3.0.2 rewrite stats until the document is rewritten again. |
rewrite_input_tokens_passes | Array | Per-call token breakdown. New rows include model_name and output_tokens; first-pass rows also include prompt_overhead_tokens and source_input_tokens when available. |
rewrite_output_tokens | Integer | Provider-reported candidate plus thinking tokens across all calls in the latest rewrite attempt, including generated output later rejected by validation. Null for pre-3.0.2 rewrite stats until the document is rewritten again. |
rewrite_cost_usd | Number | Stored list-price estimate across every model used by the latest rewrite attempt. Null for legacy attempts or when a configured model has no price. |
rewrite_completed_at | String | ISO timestamp when the latest rewrite attempt completed or was rejected after generation. |
processing_error | String | Error message when digitization or rewriting failed, or a BUDGET_BLOCKED: reason while work is deferred for budget capacity. |
embedding_status | String | Per-document embedding state: pending, in_progress, success, failed, or null. |
embedding_error | String | Error message if embedding failed. |
embedded_at | String | ISO timestamp of the latest successful embedding. |
embedding_chunk_count | Integer | Number of chunks embedded for this document. |
embedding_dense_vector_count | Integer | Number of dense vectors written for the document. |
embedding_bm25_language_counts | Object | Embedded BM25 chunk counts by detected language. |
qdrant_document_id | String | Current vector-store document identifier. |
deletion_requested_at | String | ISO timestamp when deletion has been requested but is still waiting for processing/vector cleanup. |
digitized_char_count | Integer | Character count of digitized content. |
draft_rewrite_char_count | Integer | Character count of draft rewrite. |
final_rewrite_char_count | Integer | Character count of final rewrite. |
When use_original_as_rewritten is enabled, the document still receives file_rewritten content and can be embedded/synced normally, but no LLM rewrite pass occurs. In that case, input_file_tokens describes the accepted source text, while rewrite_model, rewrite_input_tokens_total, rewrite_input_tokens_passes, rewrite_output_tokens, rewrite_cost_usd, and rewrite_completed_at remain null or unchanged until a real rewrite runs.
Document-list and combined-KB responses also include lifetime_usage for each
document: event_count, priced_event_count, unpriced_event_count,
rewrite_event_count, digitization_event_count, and cost_usd_total.
Administrator responses additionally expose rewrite_provider and
rewrite_provider_inferred. A processing_error beginning with
BUDGET_BLOCKED: means the document is waiting for budget capacity rather than
requiring an immediate client retry.
Error Responses
Most errors use FastAPI's standard JSON shape with a detail field. The exact message varies by endpoint.
Unauthorized (401)
{
"detail": "Invalid API key"
}
Forbidden (403)
{
"detail": "Access denied to partner 'my-partner'"
}
Not Found (404)
{
"detail": "Knowledge base not found"
}
Rate Limited (429)
Rate-limit responses are produced by the shared SlowAPI rate-limit handler.