What RAVEN does
RAVEN reads your documents and answers questions about them. You add files — PDFs, Word docs, Excel sheets, images, plain text — and RAVEN parses them, breaks them into passages, and indexes them so they're searchable by meaning. Your application then asks questions in plain English over HTTPS, and RAVEN replies with a written answer plus citations back to the exact source passages.
You don't run any AI models, manage a vector database, or pick an embedding service. RAVEN handles parsing, chunking, embedding, retrieval, reranking, and answer generation behind one API. Your app just makes authenticated HTTPS calls.
RAVEN is modular. You can use the whole pipeline (documents in, cited answers out) or just one piece — retrieval only, batch question-answering, structured table/key-value lookup, or document management. Pick what you need; ignore the rest. See Building blocks below.
Connecting your application
1 — Get a key and a namespace from an operator
Ask a RAVEN operator for an API key. You give them an application id (kebab-case, like traceline or marketing-tool) and one or more project ids. Each application_id + project_id pair forms a namespace — written application_id/project_id — which is the isolation boundary for your documents. The operator hands back one key scoped to your application's namespaces. Treat it like a password.
2 — Verify the key
curl "$RAVEN_HOST/v1/ready" \
-H "X-API-Key: $RAVEN_KEY"
# → 200 {"status": "ready", "services": {...}}
3 — Add documents
Stage your files in an allow-listed S3 bucket, then ingest one by name:
curl -X POST "$RAVEN_HOST/v1/ingest/source" \
-H "X-API-Key: $RAVEN_KEY" \
-H "Content-Type: application/json" \
-d '{
"application_id": "myapp",
"project_id": "q1-rfp",
"source_uri": "s3://raven-sources-.../myapp/q1-rfp/contract.pdf"
}'
# → 202 {"job_id": "...", "status": "queued", ...}
This returns immediately with a job id; indexing happens in the background (a few seconds for small text files, longer for large PDFs). Poll GET /v1/jobs/{job_id} for progress, or subscribe a webhook (step 5). To bulk-discover everything under a prefix, use POST /v1/ingest/source/prefix — note it only catalogs files; you then select which ones to index (see Building blocks → Ingestion).
4 — Ask questions
Let RAVEN write the answer with citations:
curl -X POST "$RAVEN_HOST/v1/chat" \
-H "X-API-Key: $RAVEN_KEY" \
-H "Content-Type: application/json" \
-d '{
"application_id": "myapp",
"project_id": "q1-rfp",
"question": "What is the warranty period?"
}'
# → 200 {"answer": "...", "citations": [...], "answer_id": "..."}
Or get just the matching passages and run your own LLM:
curl -X POST "$RAVEN_HOST/v1/search" \
-H "X-API-Key: $RAVEN_KEY" \
-H "Content-Type: application/json" \
-d '{
"application_id": "myapp",
"project_id": "q1-rfp",
"query": "warranty period",
"top_k": 5
}'
# → 200 {"results": [...], "count": 5}
5 — (Optional) Receive webhooks
Instead of polling, have RAVEN POST you a signed event when an ingest job or async batch reaches a terminal state. Webhook registration is operator-managed (admin-only) — ask an operator to register your receiver URL and the events you want. See Building blocks → Webhooks for the signature scheme.
/v1/search. A full managed-chat integration adds /v1/chat. Webhooks, batch, streaming, and personas are all optional layers on top.
Capabilities you can pick from
Each row is a self-contained capability. Use one, several, or all of them.
| Capability | Use this when… | Endpoint |
|---|---|---|
| Managed chat | You want RAVEN to write the answer, with citations back to the source passages. | POST /v1/chat |
| Retrieval only | You already have your own LLM/agent and just want the matching passages. | POST /v1/search |
| Batch chat | You have many questions to answer in one round-trip (sync) or as a background job (async). | POST /v1/chat/batch (up to 50) |
| Streaming answers | You want tokens to appear as they're written for a live UX. | POST /v1/chat with "stream": true |
| Structured lookup | You need raw rows from indexed tables or extracted key/value forms. | POST /v1/search/tables, POST /v1/search/key-values |
| Ingestion | Add documents: a single S3 object, a batch of objects, or bulk-discover an S3 prefix into the catalog. | POST /v1/ingest/source, /source/batch, /source/prefix |
| Catalog & selection | You want to list discovered files, preview cost, then choose which to index. | POST /v1/sources/catalog/upsert, /estimate, /select, /deselect |
| Personas & formats | You want a custom system prompt, tool allowlist, or a fixed output shape (terse / JSON-schema). | domain_knowledge_id + response_format on chat |
| Webhooks | You want push notifications on ingest / answer-batch status instead of polling. | operator-registered; events below |
| Audit trail | You need to trace an answer back to its citations, or list events for a namespace. | GET /v1/audit/answers, /v1/audit/answers/{id}, /v1/audit/events |
| Document & job inspection | You want to see what's indexed, check ingest progress, or remove a document. | GET /v1/documents, /v1/jobs, DELETE /v1/documents/{id} |
| Self-service namespace ops | Your app manages its own namespace lifecycle (pause, resume, reindex, delete). | /v1/admin/* scoped to your namespace |
Batch chat — sync and async
Send up to 50 questions in one call. By default the call blocks and returns every answer inline. For large batches that would outlast your load balancer's idle timeout, set "async_": true (or add ?async=true): RAVEN returns 202 + a batch_id immediately, drains the batch in the background, and you poll GET /v1/answer/batch/{batch_id} (or subscribe a webhook).
curl -X POST "$RAVEN_HOST/v1/chat/batch" \
-H "X-API-Key: $RAVEN_KEY" \
-H "Content-Type: application/json" \
-d '{
"application_id": "myapp",
"project_id": "q1-rfp",
"questions": ["What is the warranty period?", "Who is the inverter vendor?"]
}'
Streaming
Add "stream": true to a /v1/chat body. The response is text/event-stream (Server-Sent Events) carrying token / tool_call / tool_result / done frames as they happen. Auth and scope are still checked before the first byte, and the final frame still includes an answer_id for the audit trail.
Personas (Domain Knowledge) & response formats
Pass domain_knowledge_id on any /v1/chat or /v1/chat/batch call to apply a tenant-authored system prompt, tool allowlist, and default output format on top of RAVEN's safety rules. Pass response_format ({"style": "narrative" | "terse" | "json", "schema": {...}}) to pin the output shape for one call. An unknown or cross-tenant domain_knowledge_id returns 404 domain_knowledge_not_found; if omitted, your tenant+app default persona applies, else RAVEN's built-in prompt. Manage personas in the Personas tab or via /v1/domain-knowledges. Full design: docs/RAVEN-DOMAIN-KNOWLEDGE-DESIGN.md.
Webhooks
When a webhook is registered for your namespace, RAVEN POSTs a JSON event to your URL on terminal status. Each delivery carries two headers:
X-Raven-Signature: sha256=<hex HMAC-SHA256(secret, "{timestamp}." + body)>
X-Raven-Timestamp: <unix epoch seconds>
To verify: reject if X-Raven-Timestamp is more than ~5 minutes (300s) off your clock, recompute the HMAC over "{timestamp}." + rawBody with your webhook secret, and compare constant-time against the digest. Event type strings:
| Event type | Fires when |
|---|---|
job.complete | An ingest job finished cleanly |
job.copies | An ingest job matched content already indexed in the namespace |
job.partial | An ingest job indexed some pages but some page ranges failed |
job.failed / job.dead_lettered | An ingest job failed terminally |
answer_batch.complete / .partial / .failed | An async batch reached terminal status |
document.deleted | A document was removed from the index |
Self-service namespace management
Your namespace-scoped key can manage its own namespace through a subset of the /v1/admin/* routes — no global admin key needed. Acting on a namespace your key doesn't cover returns 403 namespace_forbidden.
| Action | Endpoint |
|---|---|
| Pause / resume ingest for a namespace | POST /v1/admin/tenants/{namespace}/pause · /resume |
| Reindex a document | POST /v1/admin/documents/{id}/reindex |
| Cancel queued jobs in a namespace | POST /v1/admin/jobs/cancel?namespace=... |
| Delete a whole namespace | DELETE /v1/admin/namespaces/{namespace} |
Headers, errors & empty namespaces
Every request needs the X-API-Key header. Optionally add X-Actor-User-Id — an opaque label identifying which of your end users triggered the call. RAVEN never authorizes on it; it's stamped on the audit row for your own traceability.
Structured error envelope
Every 4xx/5xx response (published in the OpenAPI spec) comes back in one shape so you can codegen typed error handling:
{
"error_code": "namespace_forbidden", // machine-readable, snake_case
"message": "tenant 'x' is not authorised for namespace 'y'",
"retryable": false, // true → safe to retry
"request_id": "req_...", // mirrors X-Request-ID; share with operators
"service": null, // upstream that caused it, when relevant
"stage": null, // ingest stage, when relevant
"details": null // curated, client-safe context
}
429 and 503 responses also carry a Retry-After header. Graceful degradation (e.g. a reranker fallback) is reported on a successful response via a top-level {"degraded": true, "warnings": [...]} envelope plus a Warning: 299 header — not an error.
Querying a namespace with nothing indexed yet
/v1/search or /v1/chat (including streaming) against a namespace that has no indexed content yet, RAVEN returns 200 with an empty result set / a clean "no indexed content yet" answer and a namespace_not_indexed degradation warning — never a 503. That lets you distinguish "nothing ingested yet" from "indexed but no match" without special-casing a failure.
Common error codes
| You see | What it means | Fix |
|---|---|---|
401 missing_api_key | No X-API-Key header | Add the header |
401 invalid_api_key | Key not recognised | Re-check the value; ask an operator if it was rotated |
403 namespace_forbidden | Your key doesn't cover this application_id/project_id | Confirm the IDs match what the operator assigned |
400 "source_uri must be an s3://…" | You passed a non-S3 URI to ingest | Use s3://bucket/key (the prefix endpoint also accepts AWS console / https S3 URLs) |
403 "Source bucket … not allowed" | The bucket isn't allow-listed | Stage the file in an allowed bucket, or ask an operator to add yours |
403 catalog_selection_required | Strict catalog mode is on for your tenant | Use the catalog flow: /sources/catalog/upsert then /select |
Job stuck in queued | Worker busy, paused, or not yet selected in the catalog | Check GET /v1/jobs/{job_id} for the current stage |
404 domain_knowledge_not_found | Unknown or cross-tenant domain_knowledge_id | List yours via GET /v1/domain-knowledges |
Recent activity
Service health
Ingest Jobs
Job detail
Documents
Document detail
Audit Trail
Review answer provenance, citation health, and tool traces.
Answer detail
Ingest
Recent ingestions
Operations console
Stuck jobs
Dead-lettered jobs
Jobs by tenant
Applications & projects
Scopes register automatically when your app calls ingest, chat, or search with a valid namespace.
Delete removes documents, the vector index, catalog rows, and jobs for that project.
Requires an admin API key and request header X-Confirm-Destroy: yes.
API keys
Webhooks
Vector indexes
Active features
Live snapshot of this backend task's feature flags and config values — figure vision, web enrichment, judge, chat, and answering. Read directly from process environment on every request; requires an admin API key.
Search Console
Personas (Domain Knowledge)
Personas are tenant-authored system prompts the chat agent uses on top of
RAVEN’s built-in safety rules. Each call to /v1/chat or
/v1/chat/batch can pass domain_knowledge_id; with no id,
the default for the calling application is applied. This list shows all
personas for your tenant (not only the current application filter).