Knowledge base

Upload the documents an agent answers from: catalogs, price lists, policies and FAQs.

View as Markdown

A knowledge document is a file you upload to one agent so it can answer from your own material instead of general knowledge: a product catalog, a price list, a returns policy, an FAQ. Documents are managed per agent under /api/agents/{agentId}/knowledge. Uploading a document attaches it to that agent in the same request, and the agent’s retrieval is switched on for you. There is no separate attach step.

How it works

  1. Validation. The file must have an allowed extension, be sent with an allowed MIME type, and its bytes must match the extension (a .pdf must start with %PDF-, a .docx must be a ZIP container, and so on). Text formats are also screened for prompt-injection and fraud content.
  2. Plan check. The workspace plan caps both the number of knowledge files and their total size, counted across every agent in the workspace.
  3. Attach. The document is stored, attached to the agent, and the agent’s retrieval is enabled. The response returns immediately with status: "processing".
  4. Indexing. Indexing continues in the background. A background reconciler re-checks documents that are still processing or failed every few minutes, so a document can take several minutes to show ready even when indexing finished sooner.
  5. Retrieval. From then on, the agent retrieves relevant passages from its documents while it talks. Knowledge is attached to the agent, not to a channel, so the same documents serve calls and text conversations.
  6. Removal. Deleting a document detaches it from the agent and removes it. When an agent’s last document is deleted, retrieval is switched off again.

The API accepts files only. There is no endpoint that ingests a URL or a raw text string. To use a web page or a snippet of text, save it as .html, .md or .txt and upload that file.

Document status

status is the value to branch on. It is derived from the indexing state (rag_index_status) and the indexing error:

rag_index_statusrag_index_errorstatusMeaning
pendingnullprocessingAccepted; indexing has not started yet. This is what the upload response returns.
processingnullprocessingIndexing is running.
succeedednullreadyIndexed and retrievable.
faileddocument_too_small, rag_limit_exceeded or cannot_index_folderreadyThe document cannot be indexed and retrying will not change that. It stays attached to the agent.
failedany other valuefailedIndexing failed. It is retried automatically in the background.

A document under about 500 bytes is reported as document_too_small: it stays attached and shows ready, but it is not indexed. When you test retrieval, use a document larger than that.

The knowledge document object

Returned by the upload, by the list, and inside result of a completed upload job.

FieldTypeNullableDescription
idstring (uuid)NoDocument ID. Use it to delete the document.
agent_idstring (uuid)NoThe agent the document is attached to. A document belongs to exactly one agent.
namestringNoThe uploaded file name, stripped of any directory part and truncated to 255 characters.
sizeintegerNoFile size in bytes. Counts toward the plan’s total knowledge size.
statusstringNoprocessing, ready or failed. See Document status.
rag_index_statusstringNoRaw indexing state: pending, processing, succeeded or failed.
rag_index_errorstringYesWhy indexing did not succeed, for example document_too_small. null while pending, processing or after success.
created_atstring (ISO 8601)NoWhen the document was uploaded. Lists are sorted by this field, newest first.
updated_atstring (ISO 8601)NoLast change to the document record.
{
"id": "4b7e2c91-3d5a-4f08-9a6e-1c2d3e4f5a6b",
"agent_id": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"name": "lista-de-precios-2026.pdf",
"size": 482311,
"status": "ready",
"rag_index_status": "succeeded",
"rag_index_error": null,
"created_at": "2026-09-14T15:02:11.204Z",
"updated_at": "2026-09-14T15:02:11.204Z"
}

Supported files

ExtensionSend with MIME typeContent check
.pdfapplication/pdfStarts with %PDF-.
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentA ZIP container.
.epubapplication/epub+zipA ZIP container.
.htmltext/htmlContains <html or <!doctype in the first 512 bytes.
.txttext/plainNo null bytes in the first 4 KB.
.mdtext/markdown or text/x-markdownNo null bytes in the first 4 KB.
.csvtext/csv or text/plainNo null bytes in the first 4 KB.
.jsonapplication/json or text/plainNo null bytes in the first 4 KB. JSON is not parsed; any text is accepted.

The accepted MIME types are exactly application/pdf, text/plain, text/csv, text/markdown, text/x-markdown, application/json, application/vnd.openxmlformats-officedocument.wordprocessingml.document, text/html and application/epub+zip. The extension is read from the file name you send, case-insensitively. Files must be at least 4 bytes and at most 20 MB.

Always set the MIME type of the file part explicitly. Many HTTP clients send application/octet-stream when they cannot guess a type (a Blob created without type, curl -F for .md, .csv, .json, .docx or .epub), and that is rejected with 400: MIME type not allowed: application/octet-stream. Allowed: .... Also pass a file name with the part: without one, clients send a name such as blob, which fails the extension check with File type not allowed.

Common tasks

Upload a document

1

Send the file as multipart/form-data

The multipart field must be named file. Do not set the Content-Type header of the request yourself; let your client generate the multipart boundary.

curl -sS -X POST "https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4/knowledge" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-F "file=@lista-de-precios-2026.pdf;type=application/pdf"
2

Read the 201 response

The document is already attached to the agent. Indexing has not started yet:

{
"data": {
"id": "4b7e2c91-3d5a-4f08-9a6e-1c2d3e4f5a6b",
"agent_id": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"name": "lista-de-precios-2026.pdf",
"size": 482311,
"status": "processing",
"rag_index_status": "pending",
"rag_index_error": null,
"created_at": "2026-09-14T15:02:11.204Z",
"updated_at": "2026-09-14T15:02:11.204Z"
}
}
3

Wait for the document to be ready

There is no single-document endpoint and no webhook for indexing. List the agent’s documents and look for your id until status is ready or failed. Indexing is re-checked every few minutes, so poll about once a minute rather than in a tight loop.

curl -sS "https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4/knowledge?limit=100" \
-H "Authorization: Bearer $JELLIU_API_KEY"

Upload in the background

Add ?async=true to queue the upload instead of waiting for it. Validation of the extension, MIME type, content and screening, and the plan’s file-count check, still run before the response; everything after that runs in a job.

1

Queue the upload

curl -sS -X POST "https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4/knowledge?async=true" \
-H "Authorization: Bearer $JELLIU_API_KEY" \
-F "file=@politica-de-devoluciones.md;type=text/markdown"
{
"data": {
"jobId": "3f1c9a52-8d7e-4b0a-9f39-2b8a4e6d1c77",
"status": "pending"
}
}
2

Poll the job

GET /api/agents/{agentId}/knowledge/jobs/{jobId} returns the job. status moves from pending to processing and ends in completed (with the document in result) or failed (with the reason in error).

curl -sS "https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4/knowledge/jobs/3f1c9a52-8d7e-4b0a-9f39-2b8a4e6d1c77" \
-H "Authorization: Bearer $JELLIU_API_KEY"
{
"data": {
"id": "3f1c9a52-8d7e-4b0a-9f39-2b8a4e6d1c77",
"tenantId": "b2a4c6d8-1e3f-4a5b-8c7d-9e0f1a2b3c4d",
"type": "knowledge-upload",
"status": "completed",
"result": {
"id": "9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a",
"agent_id": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"name": "politica-de-devoluciones.md",
"size": 18244,
"status": "processing",
"rag_index_status": "pending",
"rag_index_error": null,
"created_at": "2026-09-14T15:10:42.018Z",
"updated_at": "2026-09-14T15:10:42.018Z"
},
"createdAt": "2026-09-14T15:10:41.550Z",
"updatedAt": "2026-09-14T15:10:42.391Z"
}
}

A job is kept for one hour after its last update, then the endpoint answers 404 NOT_FOUND. Background uploads are attempted once: a failed job is not retried, so upload the file again. Errors that the synchronous upload returns as HTTP errors, such as the plan’s total-size cap or an agent that is still provisioning, arrive here as status: "failed" with the message in error.

List an agent’s documents

GET /api/agents/{agentId}/knowledge uses offset pagination:

limit
integerDefaults to 50

1 to 100.

offset
integerDefaults to 0

0 to 100000.

Documents come newest first as { "data": [ ... ] }, with no total. Stop when a page returns fewer than limit items. Deleted documents are never listed.

curl -sS "https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4/knowledge?limit=50&offset=0" \
-H "Authorization: Bearer $JELLIU_API_KEY"
{
"data": [
{
"id": "9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a",
"agent_id": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"name": "politica-de-devoluciones.md",
"size": 18244,
"status": "processing",
"rag_index_status": "processing",
"rag_index_error": null,
"created_at": "2026-09-14T15:10:42.018Z",
"updated_at": "2026-09-14T15:10:42.018Z"
},
{
"id": "4b7e2c91-3d5a-4f08-9a6e-1c2d3e4f5a6b",
"agent_id": "7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4",
"name": "lista-de-precios-2026.pdf",
"size": 482311,
"status": "ready",
"rag_index_status": "succeeded",
"rag_index_error": null,
"created_at": "2026-09-14T15:02:11.204Z",
"updated_at": "2026-09-14T15:02:11.204Z"
}
]
}

Replace or delete a document

Documents cannot be edited. To update one, upload the new version, then delete the old one. Uploading first means the agent is never left without the content; deleting first frees plan capacity if you are at the cap.

curl -sS -X DELETE \
"https://api.jelliu.co/api/agents/7c1d9f30-5e2a-4a7e-9c8f-91a0b1c2d3e4/knowledge/4b7e2c91-3d5a-4f08-9a6e-1c2d3e4f5a6b" \
-H "Authorization: Bearer $JELLIU_API_KEY"

A successful delete returns 204 No Content with an empty body. The document is removed from the voice runtime first; if that fails, the document stays in your list and the request can be retried safely. The agentId in the path must be the agent the document belongs to.

A document belongs to one agent. To give two agents the same material, upload the file to each of them. Each copy counts toward the plan’s file count and total size.

Errors

CodeStatusWhen
VALIDATION_FAILED400Invalid agent ID or Invalid agent ID or document ID: a path ID is not a UUID.
VALIDATION_FAILED400No file uploaded: the request has no multipart part named file.
VALIDATION_FAILED400File type not allowed. Allowed: ...: the file name’s extension is not supported, or the part has no file name.
VALIDATION_FAILED400MIME type not allowed: ...: the part’s MIME type is not in the accepted list, typically application/octet-stream.
VALIDATION_FAILED400File content does not match extension ...: for example not a PDF (missing %PDF- header), null byte in text file or file too small.
VALIDATION_FAILED400Document rejected by content screening: ...: a text document was flagged as prompt injection or fraud.
VALIDATION_FAILED400Document does not belong to this agent: the delete path names a different agent.
VALIDATION_FAILED400Request validation failed: limit, offset or jobId is out of range or malformed. details lists the issues.
UNAUTHORIZED401Missing or invalid API key. See Authentication.
FORBIDDEN403A read key attempted an upload or delete.
BILLING_ERROR403Knowledge file limit reached (5 files on the starter plan). ...: the workspace is at its file count.
BILLING_ERROR403Knowledge base size limit reached (10 MB on the starter plan). ...: this file would take the workspace past its total size.
BILLING_ERROR403Your free trial has ended (or no plan is active). ...: the workspace has no active plan.
AGENT_NOT_FOUND404The agent does not exist, was deleted, or belongs to another workspace.
NOT_FOUND404Document not found on delete, or Job not found when the job ID is unknown, belongs to another workspace, or expired.
AGENT_PROVISIONING409Agent is still being configured — try uploading again in a few seconds. Retry after Retry-After (5 seconds).
RATE_LIMIT_EXCEEDED429Too many agent operations, please slow down. See Limits.
INTERNAL_ERROR500The file is larger than 20 MB, or the file was sent in a field other than file.
VOICE_AI_ERROR502The voice runtime refused the upload or the delete. The message is the generic Internal server error. Safe to retry.

BILLING_ERROR responses carry metadata with limit, current and tier. For the file-count cap limit and current are file counts; for the size cap they are megabytes.

An oversized file and a misnamed multipart field are rejected before validation runs, so they surface as 500 INTERNAL_ERROR rather than 400 VALIDATION_FAILED. Check the size (20 MB) and the field name (file) on your side before uploading.

See Errors for the envelope and retry guidance.

Limits

Rate limits. Uploads and deletes count against the shared 10 per minute budget for agent, campaign and webhook configuration changes, in addition to the plan’s general API limit. Listing documents and polling jobs use only the general limit. See Rate limits.

Scopes. Listing documents and polling jobs need a read key. Uploading and deleting need write. See Authentication.

Plan limits. Both caps apply to the whole workspace, across all agents:

PlanKnowledge filesTotal knowledge size
No active plan00
Starter510 MB
Growth2550 MB
Business100200 MB
Enterprise9,999Unlimited

Deleted documents free their slot and their size immediately.

Per request.

LimitValue
File size20 MB per file
Files per request1
File nameTruncated to 255 characters
List page size1 to 100 documents
Upload job retention1 hour after its last update

Webhooks

No webhook events are emitted for knowledge documents. To follow indexing, list the agent’s documents as shown in Wait for the document to be ready, or poll the job when you upload with ?async=true. See Webhooks for the events Jelliu does send.