CRTX
DocsSign in →

API reference

The CRTX backend is a FastAPI application exposing five routers: /collections, /ingest, /query, /chat, /evals. All paths are relative to your backend origin (Base URL).

  • Auth: every endpoint requires Authorization: Bearer <token>. See Authentication.
  • Interactive docs: FastAPI serves auto-generated OpenAPI at Base URL/docs (Swagger UI) and Base URL/openapi.json (the raw spec — use it to generate typed clients).
  • Content type: JSON unless noted (/ingest/ is multipart/form-data; /query/ responds with text/event-stream).

#Common status codes

CodeMeaning
200Success.
401Missing/invalid/expired token.
403Authenticated but not allowed (not owner / no access / needs admin / needs ingest permission).
404Resource not found (or not visible to you).
413Upload exceeds the 50 MB limit.
415Unsupported file type.
422Request body failed validation.
502Upstream storage upload failed.
503Redis/worker unavailable — ingestion disabled.

#Collections

#POST /collections/

Create a collection.

// body
{ "name": "Q3 Financials" }   // 1–200 chars, required

Returns the created collection row (id, name, config, user_id, created_at, …). The new collection's Pinecone namespace equals its id.

#GET /collections/

List collections you own and collections shared with you. Shared entries include "shared": true and your "permission" (query | ingest).

#DELETE /collections/{id}

Owner only. Deletes the collection, cascades child rows, and purges the entire Pinecone namespace. Returns { "deleted": "<id>" }.

#GET /collections/{id}/config

Admin only (app_metadata.is_admin). Returns the retrieval config, merged over defaults:

{ "chunk_size": 1000, "retrieval_strategy": "similarity" }

#PUT /collections/{id}/config

Admin only. Update the retrieval config.

// body
{
  "chunk_size": 1000,
  "retrieval_strategy": "similarity"  // "similarity" | "mmr" | "threshold"
}

Returns the stored config.

#GET /collections/{id}/documents

List documents in a collection (owner or member). Each document includes an open_url: a 1-hour signed URL for PDFs (from the documents bucket) or the original URL for URL-sourced documents.

#DELETE /collections/{id}/documents/{document_id}

Owner only. Removes the original from storage, deletes the document's Pinecone vectors (resolved via document_chunks), and deletes the row. Returns { "deleted": "<document_id>" }.

#Sharing

MethodPathNotes
POST/collections/{id}/sharesOwner only. Body { "permission": "query" | "ingest" }. Returns a share row with a share_token.
GET/collections/{id}/sharesOwner only. Returns { shares: [...], members: [...] }; members include resolved email.
DELETE/collections/{id}/shares/{share_id}Owner only. Revokes a link. Returns { "deleted": "<share_id>" }.
DELETE/collections/{id}/members/{member_id}Owner only. Removes a member and their chats in this collection. Returns { "removed": "<member_id>" }.
POST/collections/join/{share_token}Accept an invite. Returns { collection, permission }, or { already_owner } / { already_member, permission }.

Full walkthrough: Sharing & collaboration.


#Ingestion

#POST /ingest/

Upload a document. multipart/form-data.

  • Query param: collection_id (optional).
  • Form field: file — PDF, DOCX, PPTX, XLSX, CSV, TXT, or MD. Max 50 MB.
  • Permission: owner, or member with ingest permission.
  • Errors: 415 unsupported type, 413 too large, 403 no permission, 502 storage failure, 503 Redis unavailable.
curl -X POST "$BASE_URL/ingest/?collection_id=$CID" \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@report.pdf"

Returns { "job_id": "<uuid>" }.

#POST /ingest/url

Ingest a public web page.

// body
{ "url": "https://example.com/page", "collection_id": "…" }  // collection_id optional

The URL must be http/https and resolve to a public host (private/loopback/ .local are rejected). Returns { "job_id": "<uuid>" }.

#GET /ingest/jobs/{job_id}

Poll job status (only your own jobs). Returns the ingest_jobs row:

{
  "job_id": "…", "collection_id": "…", "source": "report.pdf",
  "status": "processing",         // queued | processing | succeeded | partial | failed
  "chunks_processed": 240, "chunks_total": 512,
  "error_message": null, "created_at": "…", "updated_at": "…"
}

Details and semantics: Ingesting documents.


#Query (streaming)

#POST /query/

Run a RAG query. Responds with text/event-stream (SSE), not JSON.

// body
{
  "question": "…",        // 1–5000 chars, required
  "collection_id": "…",   // optional; empty = personal namespace
  "session_id": "…"       // optional; ties the exchange to a chat session
}

Access: if collection_id is set, you must own it or be a member (403 otherwise).

Response — SSE events (each block is event: <type>\ndata: <json>\n\n):

event:data:
metadata{ "sources": [...], "embedding_latency_ms": <int>, "retrieval_latency_ms": <int> } — sent before the first token
token{ "token": "<str>" } — one per output token
done{ "generation_latency_ms": <int>, "time_to_first_token_ms": <int> }
error{ "message": "Generation failed" } — only if generation fails mid-stream

Each source object:

{
  "source": "report.pdf",
  "chunk_index": 42,
  "text": "…",
  "score": 0.83,
  "chunk_type": "text",        // or "image_description"
  "image_url": null            // set for figure/scanned-page sources
}

After the stream ends, the exchange is persisted and scored asynchronously (see Evaluation). Consumer examples: Querying & chat.


#Chat & sessions

All paths are scoped to a collection; access requires owner or member.

MethodPathBody / notesReturns
POST/chat/{collection_id}/sessionsNew session row
GET/chat/{collection_id}/sessions[{ id, title, created_at, updated_at }], newest first
GET/chat/{collection_id}/sessions/{session_id}Session owner only[{ id, role, content, sources, created_at }]
PATCH/chat/{collection_id}/sessions/{session_id}{ "title": "…" } (1–100 chars){ updated, title }
DELETE/chat/{collection_id}/sessions/{session_id}Session owner only{ deleted }
GET/chat/{collection_id}/members[{ user_id, email, role }] (excludes you)
POST/chat/{collection_id}/sessions/{session_id}/share{ "target_user_id": "<uuid>" }{ shared: true, new_session_id }

Notes:

  • Sessions are per-user; you can only read/modify sessions you own.
  • Sharing a session copies it (with messages + sources) to a target who must already be a member/owner of the collection.

#Evaluations

Access requires owner or member of the collection.

#GET /evals/{collection_id}/stats

Aggregated metrics for the dashboard:

{
  "total_queries": 128,
  "scored_queries": 124,
  "avg_faithfulness": 0.91,
  "avg_context_relevance": 0.86,
  "avg_total_latency_ms": 2450,
  "avg_retrieval_latency_ms": 180,
  "avg_generation_latency_ms": 2200,
  "trend": [{ "date": "2026-07-01", "avg_faithfulness": 0.89,
              "avg_context_relevance": 0.84, "count": 40 }],
  "worst_queries": [{ "id": "…", "question": "…", "faithfulness_score": 0.35,
                      "context_relevance_score": 0.40, "total_latency_ms": 3100,
                      "engine": "langchain", "created_at": "…" }]
}

Aggregation currently reads up to the most recent 500 eval rows.

#GET /evals/{collection_id}

Paginated raw eval records.

  • Query params: limit (1–200, default 50), offset (≥0, default 0).
  • Returns: [{ id, question, answer, faithfulness_score, context_relevance_score, total_latency_ms, retrieval_latency_ms, generation_latency_ms, engine, retrieval_strategy, top_k, scorer_error, created_at }], newest first.

#Notes for API clients

  • SSE, not chunked JSON. /query/ streams text/event-stream. Don't call res.json() — read the body as a stream and split on \n\n.
  • Poll ingestion; don't block. /ingest/* returns a job_id immediately. Poll /ingest/jobs/{job_id} until a terminal status.
  • Signed URLs expire. Document open_urls are valid for one hour — fetch them on demand, don't cache long-term.
  • Generate a typed client from Base URL/openapi.json (e.g. openapi-typescript, openapi-python-client) rather than hand-writing request code.
  • Everything is per-user. Access is enforced from the token's sub; there is no cross-tenant listing. For headless/scoped access patterns, see Programmatic access.