Cookbook
RAG quickstart
Sign in, create a knowledge base, upload a document, wait for the indexing and ask a question — with curl, then the same in Python.
Last updated: 2026-10-03
From a file on your disk to an answer with its sources, through the app API. You need:
- an account on ITS INCOM AI with a verified email;
curlandjq;- a document: PDF, DOCX, TXT or Markdown, up to 50 MB.
1. Sign in
export BASE="https://my.ai.itsincom.org/api/v1"
export TOKEN=$(curl -s $BASE/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "…"}' | jq -r .access_token)
echo "$TOKEN"
If it prints null, the email or the password is wrong. The token lasts 24 hours by default: Signing in explains how to renew it.
2. Create a knowledge base
SLUG=$(curl -s $BASE/rag/kb \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Quickstart"}' | jq -r .slug)
echo "$SLUG"
The slug is the name plus six random characters, for example quickstart-3f9a1c. Every other call uses it.
3. Upload a document
DOC=$(curl -s $BASE/rag/kb/$SLUG/docs \
-H "Authorization: Bearer $TOKEN" \
-F file=@./your-document.pdf | jq -r .id)
echo "$DOC"
The answer is 202: the file is accepted, and the indexing waits its turn in a queue.
4. Wait until it is ready
while true; do
STATUS=$(curl -s $BASE/rag/kb/$SLUG/docs/$DOC \
-H "Authorization: Bearer $TOKEN" | jq -r .status)
echo "$(date +%T) $STATUS"
[ "$STATUS" = "ready" ] && break
if [ "$STATUS" = "failed" ]; then
curl -s $BASE/rag/kb/$SLUG/docs/$DOC -H "Authorization: Bearer $TOKEN" | jq -r .error
break
fi
sleep 3
done
The status goes pending → parsing → chunking → embedding → ready. How long it takes depends on the document and on the queue. For scale: on 22 September 2026 a five-article contract, two passages long, was indexed in 0.20 s (Three examples); a long PDF takes much longer.
5. Ask
curl -s $BASE/rag/kb/$SLUG/chat \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"question": "What is this document about?", "model": "gemma-4-26b"}' \
| jq '{answer, sources: [.sources[] | {document_filename, chunk_idx, score}]}'
answer cites the passages as [file name: parte N]; sources lists them, the best first, with the score of the reranker. Without model, the answer is written by apertus-70b-instruct. Every field is in Knowledge bases API.
The same in Python
With the account's credentials in EMAIL and PASSWORD:
import os
import time
import requests
BASE = "https://my.ai.itsincom.org/api/v1"
# 1. Sign in
login = requests.post(
f"{BASE}/auth/login",
json={"email": os.environ["EMAIL"], "password": os.environ["PASSWORD"]},
timeout=30,
)
login.raise_for_status()
H = {"Authorization": f"Bearer {login.json()['access_token']}"}
# 2. Create a knowledge base
kb = requests.post(f"{BASE}/rag/kb", json={"name": "Quickstart"}, headers=H, timeout=30)
kb.raise_for_status()
slug = kb.json()["slug"]
# 3. Upload a document
with open("your-document.pdf", "rb") as f:
up = requests.post(f"{BASE}/rag/kb/{slug}/docs", files={"file": f}, headers=H, timeout=300)
up.raise_for_status()
doc_id = up.json()["id"]
# 4. Wait for the indexing
while True:
doc = requests.get(f"{BASE}/rag/kb/{slug}/docs/{doc_id}", headers=H, timeout=30).json()
print("status:", doc["status"])
if doc["status"] == "ready":
break
if doc["status"] == "failed":
raise RuntimeError(doc["error"])
time.sleep(3)
# 5. Ask
resp = requests.post(
f"{BASE}/rag/kb/{slug}/chat",
json={"question": "What is this document about?", "model": "gemma-4-26b"},
headers=H,
timeout=120,
)
resp.raise_for_status()
result = resp.json()
print(result["answer"])
for s in result["sources"]:
print(f" {s['document_filename']}, passage {s['chunk_idx']} (score {s['score']:.3f})")
If something goes wrong
| What you see | What it means |
|---|---|
403 with email_unverified |
The account's email is not confirmed yet: confirm it, then retry. |
422 on the upload |
The file is larger than 50 MB, or its content is not PDF, DOCX, TXT or Markdown. |
failed with Documento vuoto dopo parsing |
No text came out of the file. Usually a scanned PDF that went through the pdftotext fallback, which does not read images: run OCR on it first — for example with ocrmypdf — and upload it again. |
A document stuck in pending |
The queue has not reached it yet. If it does not move, write to segreteria@itsincom.it. |
An answer saying the information is not in the documents, with sources empty |
The search found nothing — or the vector database did not answer: Service status shows which. |
500 on a question |
The answer could not be generated. Check that model is in the catalogue. |
429 |
Too many requests in a minute: wait for Retry-After. The limits are in Knowledge bases API. |
Clean up
curl -s -X DELETE $BASE/rag/kb/$SLUG/docs/$DOC -H "Authorization: Bearer $TOKEN"
This removes the document, its passages, its vectors and the file. The knowledge base itself can be deleted only from the dashboard.
Next
- Tuning RAG answers: what you can change, and how to find where a wrong answer comes from.
- Knowledge bases (RAG): what happens inside, and what does not work yet.