Ingest uploaded documents as the pack's next immutable version
const url = 'https://api.vocapable.com/v1/knowledge-packs/example/documents';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"documents":[{"file_name":"example","content":"example","content_base64":"example","format":"pdf"}],"budget_tokens":1}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.vocapable.com/v1/knowledge-packs/example/documents \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "documents": [ { "file_name": "example", "content": "example", "content_base64": "example", "format": "pdf" } ], "budget_tokens": 1 }'Upload pdf/docx/csv/md/txt and publish the extraction as the next version.
Everything that can refuse the upload - decoding, extraction, sectioning, the real
token count, the hard cap - runs first and touches no database. Only a pack that has
already compiled inside the cap reaches create_version, which re-checks the cap
itself before its own first statement. The ordering CANON fact 12 depends on therefore
holds twice over: an over-cap upload consumes no version number and writes nothing.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”POST /v1/knowledge-packs/{id}/documents - upload documents as the next version.
budget_tokens is the caller’s own ceiling, not the platform’s. The 16,000-token hard
cap (docs/08-ai-quality.md, CANON fact 12) always applies and bounds this field; leaving
it unset means only the hard cap is enforced, which is exactly what the hand-authored
version endpoint does.
object
One uploaded file.
The bytes arrive base64-encoded (content_base64) or, for the three text formats, as
plain text (content) - never as multipart/form-data, which needs python-multipart
and is not a workspace dependency. ContactImportRequest made the same call for CSV
uploads, and the extractor takes bytes either way, so the wire shape can change later
without touching ingestion.
Responses
Section titled “Responses”Successful Response
The created version plus the ingest accounting behind it.
object
A compiled version. Immutable once ready - an edit is the next version.
object
One distilled section of a pack, plus where it came from.
text is the artifact, not a summary of one: knowledge_pack_versions carries
sources and no separate body column, so these sections are the compiled pack.
Phrase them spoken-answer-ready - short declaratives an agent can say verbatim.
Compiled above the 8k default budget but inside the 16k hard cap.
Permitted, and worth telling the tenant: a cap-size pack roughly doubles cold prefill and halves the number of warm pack prefixes a node holds.
What one uploaded document cost, so “distill harder” names a file.
The parts need not sum to the version’s compiled_token_count: a BPE tokenizer merges
across the joins between documents, so the pack is counted once as a whole.
object
Example
{ "version": { "status": "compiling", "sources": [ { "kind": "pdf" } ] }}Validation Error
object
object
object
Examplegenerated
{ "detail": [ { "loc": [ "example" ], "msg": "example", "type": "example", "input": "example", "ctx": {} } ]}