Skip to main content

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 fieldTypeWhat it limits
character_limitIntegerAccepted digitized characters for non-deleted documents.
token_limitIntegerLifetime recorded rewrite and embedding input plus output tokens.
dollar_limit_usdDecimal string or numberLifetime 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",
"user_email": "[email protected]",
"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"
ParameterTypeDefaultDescription
nameStringKnowledge base name. Required.
character_limitIntegerOptional non-negative stored digitized-character limit.
token_limitIntegerOptional non-negative lifetime model-token limit.
dollar_limit_usdDecimalOptional non-negative lifetime customer-charge limit, with up to 8 decimal places.
expert_nameStringKnowledge base-level expert/author metadata.
user_emailStringKnowledge 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 fieldTypeDefaultDescription
nameStringFolder name. Required.
typeStringregularregular or youtube_channel.
channel_urlStringRequired for youtube_channel: an @handle, /channel/UC…, /user/…, or /c/… YouTube channel URL.
model_tierStringstandardstandard 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:

FieldDescription
id, name, typeDurable source ID, folder name, and youtube_channel.
channel_url, channel_idSubmitted channel alias and resolved canonical channel ID when available.
enabled, model_tier, status, last_errorCurrent sync controls and state. Status may be pending, syncing, synced, incomplete, budget_blocked, paused, error, or duplicate.
last_sync_at, next_sync_atLast complete scan and next scheduled check.
countsVideo counts by pending, deferred, imported, duplicate, or suppressed status.
duplicate_source, duplicate_document_idsLink 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 "auto_rewrite=true" \
-F "character_limit=250000" \
-F "model_tier=standard"

Form Parameters

ParameterTypeDefaultDescription
typeStringfile or url. Required.
folderStringTarget folder name. Required.
fileFileFile to upload. Required when type=file.
urlStringURL to fetch. Required when type=url.
nameStringDocument name. Auto-detected from file/URL if omitted.
expert_nameStringContent author or speaker name.
user_emailStringEmail of the uploading user.
auto_rewriteStringfalseAutomatically queue for rewriting after digitization. Pass "true" to enable.
model_tierStringstandardLLM model tier: standard or economy.
use_original_as_rewrittenStringfalseSkip LLM rewriting and use the original/digitized content as final rewritten content. Pass "true" to enable.
character_limitIntegerOptional 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
}'
note

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.

ParameterTypeDefaultDescription
nameStringDocument name. Required.
folderStringTarget folder name. Required.
typeStringfile or url. Required.
urlStringURL (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

ParameterTypeDefaultDescription
formatstringrawmarkdown 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".

note

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
ParameterTypeDefaultDescription
documentObjectDocument object (JSON body).
actionStringdigitizeProcessing action: digitize or rewrite.
partnerStringPartner name.
kbStringKnowledge base name.
content_typeStringautoauto, article, youtube, or book.
person_nameStringAuthor/speaker name for the rewrite prompt.
character_limitIntegerOptional 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 → youtube template
  • PDF, EPUB, and Word documents → book template
  • Everything else → article template

Bulk Rewrite (Folder)

POST /api/bulk/rewrite/folder/{partner}/{kb}/{folder}
ParameterTypeDefaultDescription
skip_rewrittenBooleantrueSkip documents that already have rewritten content.
content_typeStringautoContent type template to use.
person_nameStringAuthor/speaker name.

These options are query parameters.

Bulk Rewrite (Knowledge Base)

POST /api/bulk/rewrite/kb/{partner}/{kb}
ParameterTypeDefaultDescription
skip_rewrittenBooleantrueSkip documents that already have rewritten content.
content_typeStringautoContent type template to use.
person_nameStringAuthor/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:

EndpointDescription
GET /api/openai-sync/{partner}/{kb}Read KB vector-store and document sync status.
POST /api/openai-sync/{partner}/{kb}/backfillQueue all rewritten documents for sync.
POST /api/openai-sync/{partner}/{kb}/retry-failedQueue 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

EndpointAccessDescription
GET /api/auth/meAny authenticated keyReturns the current key's partner scope and isAdmin flag.
GET /api/partnersAny authenticated keyLists all partners for admins, or only the caller's partner for scoped keys.
GET, POST, PUT, DELETE /api/partners/{partner}Admin onlyRead, create, update, or delete a partner. Partner creation returns the generated API key once.
POST /api/partners/{partner}/regenerate-keyAdmin onlyReplaces the partner key and returns the new key once.
GET /api/prompts/{content_type}Admin onlyReturns the configured rewrite prompt. auto resolves to article.
GET /api/queueAdmin onlyReturns combined queue status.
GET /api/queue/jobs?limit=100Admin onlyReturns combined jobs; limit is 1–1000.
GET /api/queue/debugAdmin onlyCorrelates durable queue markers and BullMQ jobs.
POST /api/queue/retry-failedAdmin onlyRetries failed rewrite queue jobs.
DELETE /api/queue/clear-orphansAdmin onlyClears 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:

FieldTypeDescription
idStringUUID identifier.
nameStringDocument name.
folderStringFolder name.
typeStringfile or url.
urlStringSource URL (if type is url).
file_originalStringOriginal uploaded filename.
file_digitizedStringDigitized content filename.
file_rewritten_draftStringDraft rewrite filename.
file_rewrittenStringFinal rewrite filename.
user_emailStringEmail of the uploading user.
in_queuesArrayActive processing queues (e.g., ["digitize"], ["rewrite"], ["embedding"]).
expert_nameStringContent author/speaker.
auto_rewriteBooleanWhether auto-rewrite is enabled.
model_tierStringstandard or economy.
digitization_providerStringProvider for the latest successful digitization when billing metadata was captured. Currently populated for Apify routes; null for other and legacy digitizations.
digitization_cost_usdNumberThis document's allocated share of the successful Apify Actor run's actual usageTotalUsd; null when unavailable or not applicable.
rewrite_modelStringLLM model used for rewriting.
input_file_tokensIntegerEstimated 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_totalIntegerProvider-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_passesArrayPer-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_tokensIntegerProvider-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_usdNumberStored 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_atStringISO timestamp when the latest rewrite attempt completed or was rejected after generation.
processing_errorStringError message when digitization or rewriting failed, or a BUDGET_BLOCKED: reason while work is deferred for budget capacity.
embedding_statusStringPer-document embedding state: pending, in_progress, success, failed, or null.
embedding_errorStringError message if embedding failed.
embedded_atStringISO timestamp of the latest successful embedding.
embedding_chunk_countIntegerNumber of chunks embedded for this document.
embedding_dense_vector_countIntegerNumber of dense vectors written for the document.
embedding_bm25_language_countsObjectEmbedded BM25 chunk counts by detected language.
qdrant_document_idStringCurrent vector-store document identifier.
deletion_requested_atStringISO timestamp when deletion has been requested but is still waiting for processing/vector cleanup.
digitized_char_countIntegerCharacter count of digitized content.
draft_rewrite_char_countIntegerCharacter count of draft rewrite.
final_rewrite_char_countIntegerCharacter 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.