API REFERENCE
The Knowledge API
Give one user their own private documents. Uploads run through the same pgvector hybrid retrieval as your shared knowledge base, but the chunks stay scoped to that user.
These endpoints manage the private documents that belong to a single end user. Every call carries a signed user_context, so the file is indexed under the audience user:<id> and never leaks into another user's retrieval. To seed the shared pool that everyone in a project can see, upload from Settings instead.
_ts and _sig on the user_context, or you get SIGNED_IDENTITY_REQUIRED; a missing or anonymous id gives USER_ID_REQUIRED. See the signed identity guide for the HMAC recipe.Origin header is rejected with 403 ORIGIN_NOT_ALLOWED — so a backend curl that works against /v1/credentials, which skips the check on purpose, fails here. Send an Origin header matching one of your allowed origins (a trailing slash on the header is stripped before comparison), or leave the allowlist empty. Every example below sends one.DATABASE_URL the server falls back to a local ChromaDB store that has no audience support: an upload with a user audience returns an error, and the list route returns an empty array rather than exposing the shared pool.Upload a document
/v1/knowledgeA multipart/form-data request with two parts: the file itself and a user_context field holding the signed identity as JSON. The file is queued for embedding and the call returns immediately with a job id. Indexing runs in the background (chunk at 400 words with an 80-word overlap, embed with BAAI/bge-m3, write to pgvector), so a fresh upload becomes retrievable a few seconds later.
| Field | Type | Description |
|---|---|---|
filerequired | file | The document. PDF, TXT, or MD. Up to 50 MB. |
user_contextrequired | string (JSON) | The signed identity for the owning user, serialized as JSON. Must include _ts and _sig. |
Limits enforced on upload:
| Field | Type | Description |
|---|---|---|
file type | extension | Judged by extension: .pdf, .txt or .md only. Anything else returns 415 UNSUPPORTED_TYPE. |
file size | bytes | Hard cap of 50 MB. A larger file returns 413 FILE_TOO_LARGE. |
docs per user | int | Up to 20 documents per user per project. The 21st returns 409 DOC_CAP_REACHED until one is deleted. |
rate limit | 10/min, 50/day | Per user per project, on a bucket separate from /v1/chat. Over either limit returns 429 RATE_LIMIT_EXCEEDED with a retry-after hint in detail. |
indexing | kill switch | While indexing is globally paused, uploads return 503 INDEXING_PAUSED. Retrieval over already-indexed documents is unaffected. |
curl -X POST https://agentifys.ai/v1/knowledge \
-H "Authorization: Bearer era_your_project_key" \
-H "Origin: https://app.example.com" \
-F "file=@handbook.pdf" \
-F 'user_context={"id":"u_42","name":"Sara","_ts":1735689600,"_sig":"a1b2c3..."}'Response. Job ids and document ids are bare 12-character hex strings with no prefix:
{
"job_id": "9f3c1e7a2b8d",
"status": "processing",
"filename": "handbook.pdf"
}| Field | Type | Description |
|---|---|---|
job_id | string | Handle for the background indexing job. 12 hex characters. |
status | string | Always "processing" on accept. The document is embedded asynchronously. |
filename | string | The original filename, echoed back. |
Check upload status
/v1/knowledge/jobs/{job_id}Polls the background indexing job by the job_id returned from the upload. The job is scoped to your project and carries no user_context, so any signed-mode caller holding the project key can read it.
curl https://agentifys.ai/v1/knowledge/jobs/9f3c1e7a2b8d \ -H "Authorization: Bearer era_your_project_key" \ -H "Origin: https://app.example.com"
Response:
{
"filename": "handbook.pdf",
"status": "done",
"chunks": 128,
"doc_id": "2b8d40f1c7a3",
"error": null
}| Field | Type | Description |
|---|---|---|
status | string | "processing" while indexing, "done" when retrievable, "failed" if it errored. |
chunks | int | Number of chunks written once done. 0 while processing. |
doc_id | string | null | The document id once done. Null until then. |
error | string | null | Failure reason when status is "failed", otherwise null. |
The two failures you will actually see are both about extraction, and both arrive as prose in error:
| Field | Type | Description |
|---|---|---|
Scanned PDF | failed | "Scanned PDF — N pages found but no text could be extracted." The file is image-based. Convert it to a text PDF or supply the text as .txt. |
Too sparse | failed | "Document is too sparse to index — N words total, but each chunk needs at least 30 words." Text came out, but no chunk reached the 30-word floor. |
List a user's documents
/v1/knowledgeReturns the documents whose audience includes the user in the request identity. That is their own uploads plus any document an admin targeted at them from the console. It never includes the shared project pool and never another user's private files.
# The signed user_context goes in the user_context query param, URL-encoded. curl "https://agentifys.ai/v1/knowledge?user_context=%7B%22id%22%3A%22u_42%22%2C%22_ts%22%3A1735689600%2C%22_sig%22%3A%22a1b2c3...%22%7D" \ -H "Authorization: Bearer era_your_project_key" \ -H "Origin: https://app.example.com"
Response, each document as its id and filename. The audience keys are deliberately not returned, so a user cannot learn who else holds a shared document:
{
"documents": [
{ "doc_id": "9f3c1e7a2b8d", "filename": "handbook.pdf" },
{ "doc_id": "2b8d40f1c7a3", "filename": "notes.md" }
]
}Delete a document
/v1/knowledge/{doc_id}Revokes the caller's access to a document. The document id goes in the path and the signed identity is passed as a user_context query param. A user can only act on a document whose audience includes them; anything else returns 404 NOT_FOUND. Either way it frees a slot against the 20-document cap.
user:<id> key is stripped from the document, and the chunks are physically deleted only once no recipient is left. A document an admin shared with several users survives for the others.curl -X DELETE "https://agentifys.ai/v1/knowledge/9f3c1e7a2b8d?user_context=%7B%22id%22%3A%22u_42%22%2C%22_ts%22%3A1735689600%2C%22_sig%22%3A%22a1b2c3...%22%7D" \ -H "Authorization: Bearer era_your_project_key" \ -H "Origin: https://app.example.com"
Response:
{ "success": true }