Skip to content

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-06

From a file on your disk to an answer with its sources, through the app API. You need:

  • an account on AI Tokens with a verified email;
  • curl and jq;
  • a document: PDF, DOCX, TXT or Markdown, up to 50 MB.

1. Sign in

bash
export BASE="https://my.aitokens.ch/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

bash
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

bash
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

bash
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

bash
curl -s $BASE/rag/kb/$SLUG/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"question": "What is this document about?", "model": "qwen3.8-27b"}' \
  | jq '{answer, sources: [.sources[] | {document_filename, chunk_idx, score}]}'

answer cites the passages as [file name — part N]; sources lists them, the best first, with the score of the reranker. Without model, the answer is written by qwen3.8-27b, the default of AI Tokens. Every field is in Knowledge bases API.

The same in Python

With the account's credentials in EMAIL and PASSWORD:

python
import os
import time

import requests

BASE = "https://my.aitokens.ch/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": "qwen3.8-27b"},
    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 info@daikolab.ch.
An answer saying the documents contain nothing about the question, with sources empty The search ran and found no passage in your ready documents.
503 with retrieval_unavailable The documents could not be searched: the vector database or the embeddings did not answer. Nothing was charged: try again in a few minutes, and see Service status.
422 on a question model is not in the catalogue, question is empty or longer than 2,000 characters, or top_k is outside 1–20: errors names the field.
500 on a question The answer could not be generated: no machine can serve the model right now. Try again later, or choose another model.
429 Too many requests in a minute: wait for Retry-After. The limits are in Knowledge bases API.

Clean up

bash
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

Search the docs

Type to search…