Overview
The oprag API powers document-backed AI chatbots for your product. Upload knowledge in the dashboard, test responses with cited sources, then deploy to receive an API key for production use.
There are two surfaces: a public chat API authenticated with project API keys
(sk_live_...), and a dashboard API authenticated with Cognito JWTs
for managing companies, projects, documents, deployments, and keys.
Retrieval is multi-tenant: each project's documents are isolated by tenant_id and
project_id in the shared Bedrock knowledge base per environment.
Base URLs
All requests use HTTPS. Pick the host for your environment:
https://api.dev.oprag.ai https://api.stg.oprag.ai https://api.oprag.ai
This page is deployed to prod. Example requests below use
https://api.oprag.ai.
Authentication
Dashboard routes
Routes under /v1/companies/* and /v1/projects/* require a Cognito JWT
from the oprag dashboard:
Authorization: Bearer <Cognito JWT>
Users must have custom:tenant_id (your companyId) set after company creation.
Only owners can invite another user with role: "owner". Inviting a user who already belongs
to another company returns 409 Conflict.
Public chat
POST /v1/chat accepts your project API key in either header:
X-Oprag-Key: sk_live_...
# or
Authorization: Bearer sk_live_... API keys are issued when you deploy a project from the dashboard.
Roles
Dashboard routes enforce company membership roles. Public POST /v1/chat uses API keys only.
| Role | Access |
|---|---|
member | Projects (read/update), documents (upload, sync, delete), dashboard test chat |
admin | Everything members can do, plus deploy, API keys, integration info, archive project |
owner | Same as admin; only owners can invite another user with role: "owner" |
Public Chat API
Ask questions against your project's indexed documents. Answers include cited source filenames.
/v1/chat Auth: X-Oprag-Key or Authorization: Bearer sk_live_...
Request body
{
"question": "What is your refund policy?",
"sessionId": "optional-session-id"
} | Field | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The user's question. Must be non-empty after trimming and within the project question max length (default 1 000 characters). |
sessionId | string | No | Pass a prior sessionId to continue a multi-turn conversation. |
Response
{
"answer": "You can cancel any time from Account → Billing...",
"sessionId": "sess_abc123",
"citations": [],
"sources": ["a1b2c3d4-billing-faq.pdf", "e5f6g7h8-terms.md"]
} | Field | Type | Description |
|---|---|---|
answer | string | Generated answer grounded in your documents. |
sessionId | string | Session identifier for follow-up questions. |
citations | object[] | Raw Bedrock citation objects. Most integrations only need sources. |
sources | string[] | S3 object basenames cited in the answer (format: {uuid}-{originalFilename}). |
Example
curl -X POST 'https://api.oprag.ai/v1/chat' \
-H 'X-Oprag-Key: sk_live_...' \
-H 'Content-Type: application/json' \
-d '{"question":"What is your refund policy?","sessionId":"optional-session-id"}' CORS & allowed origins
API Gateway allows browser CORS from any origin at the edge. Lambda enforces per-project
allowedOrigins on POST /v1/chat:
- Empty list — server-to-server calls without an
Originheader are allowed; browser embeds are denied (403). - Non-empty list — browser requests must send an
Originthat exactly matches an entry (scheme and host; trailing slashes matter). Server-to-server calls withoutOriginare still allowed.
Set allowedOrigins on project create or update before embedding the chat widget on customer sites.
Getting an API key
- Upload documents to your project in the dashboard and sync (or deploy — deploy also ingests pending uploads).
- Deploy via
POST /v1/projects/{id}/deploy(admin role). Issues a newsk_live_*key, revokes prior active keys, and auto-ingests uploaded documents. - Use the key in your integration. Keys work as soon as deploy completes — you do not
need to wait for
livestatus if documents are still indexing.
Manage keys from the dashboard or API:
GET /v1/projects/{id}/keys— list keys (prefix only, never the full secret)POST /v1/projects/{id}/keys/rotate— rotate (requires an existing active key)DELETE /v1/projects/{id}/keys/{keyId}— revoke a keyGET /v1/projects/{id}/integration— endpoint URL and curl example
API routes
Full route reference. Dashboard routes require Authorization: Bearer <Cognito JWT>;
POST /v1/chat and GET /health are public.
RAG-dependent routes return 503 when the knowledge base is not enabled in an environment.
Route list is defined in site/src/data/api-docs.ts — keep in sync with
backend/src/index.ts.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /health | Public | Liveness check |
| POST | /v1/chat | API key | Public project chatbot — question max length enforced per project (default 1 000 chars) |
| POST | /v1/companies | JWT | Create company (signup) |
| GET | /v1/companies/me | JWT | Current company |
| GET | /v1/companies/users | JWT | List team members |
| POST | /v1/companies/users/invite | JWT | Invite user |
| POST | /v1/projects | JWT · member | Create project (settings and allowed origins require admin) |
| GET | /v1/projects | JWT · member | List projects |
| GET | /v1/projects/{id} | JWT · member | Get project |
| PATCH | /v1/projects/{id} | JWT · admin | Update project name, description, CORS origins, system prompt, model, question cap, retrieval and indexing settings |
| DELETE | /v1/projects/{id} | JWT · admin | Archive project |
| POST | /v1/projects/{id}/documents/upload-url | JWT · member | Presigned upload URLs |
| POST | /v1/projects/{id}/documents/{docId}/confirm | JWT · member | Confirm S3 upload |
| GET | /v1/projects/{id}/documents/{docId}/preview-url | JWT · member | Presigned preview URL (5 min TTL, works without RAG) |
| GET | /v1/projects/{id}/documents | JWT · member | List documents |
| DELETE | /v1/projects/{id}/documents/{docId} | JWT · member | Delete document (S3 + KB) |
| POST | /v1/projects/{id}/documents/sync | JWT · member | Ingest uploaded documents (202 Accepted) |
| POST | /v1/projects/{id}/chat | JWT · member | Dashboard test chat — question max length enforced per project (default 1 000 chars) |
| GET | /v1/projects/{id}/test-prompts | JWT · member | List suggested and saved prompt tests |
| POST | /v1/projects/{id}/test-prompts | JWT · admin | Create saved prompt test; prompt max length enforced per project |
| POST | /v1/projects/{id}/test-runs | JWT · member | Run saved or ad hoc prompt tests using project chat settings |
| POST | /v1/projects/{id}/deploy | JWT · admin | Deploy, auto-ingest docs, issue API key |
| GET | /v1/projects/{id}/keys | JWT · admin | List API keys (prefix only) |
| POST | /v1/projects/{id}/keys/rotate | JWT · admin | Rotate API key |
| DELETE | /v1/projects/{id}/keys/{keyId} | JWT · admin | Revoke key |
| GET | /v1/projects/{id}/integration | JWT · admin | Integration info (endpoint, curl) |
Document upload flow
Dashboard routes for ingesting files into your project knowledge base (member role):
- Request upload URLs —
POST /v1/projects/{id}/documents/upload-url - Upload to S3 —
PUTthe file touploadUrlandmetadataBody(verbatim JSON string) tometadataUploadUrl(15-minute TTL). - Confirm upload —
POST /v1/projects/{id}/documents/{docId}/confirm— verifies S3 objects, marksuploaded, returns the document record. - Sync to knowledge base —
POST /v1/projects/{id}/documents/sync— returns 202 Accepted; ingestion runs asynchronously (wait 1–5 minutes before chatting).
Upload-url request
{
"filename": "billing-faq.pdf",
"contentType": "application/pdf"
} | Field | Required | Description |
|---|---|---|
filename | Yes | Original filename (used in S3 key suffix) |
contentType | No | Defaults to application/octet-stream |
Upload-url response
{
"documentId": "doc_abc123",
"uploadUrl": "https://...",
"metadataUploadUrl": "https://...",
"metadataBody": "{\"metadataAttributes\":{\"tenant_id\":\"...\",\"project_id\":\"...\"}}",
"key": "documents/{companyId}/{projectId}/{uuid}-billing-faq.pdf",
"metadataKey": "documents/.../billing-faq.pdf.metadata.json",
"bucket": "ashutech-dev-oprag-docs-...",
"expiresInSeconds": 900,
"instructions": "1) PUT file to uploadUrl. 2) PUT metadataBody to metadataUploadUrl. 3) POST confirm. 4) POST sync."
}
PUT metadataBody as the raw body to metadataUploadUrl — do not
JSON.stringify it again. S3 keys use {uuid}-{filename}.
Sync response (202 Accepted)
{
"documentCount": 2,
"statuses": ["STARTING"],
"companyId": "...",
"projectId": "...",
"message": "Project-scoped ingestion started. Wait 1–5 minutes before chatting."
} documentCount reflects uploaded/indexed documents only — not abandoned presigns.
POST .../deploy also confirms pending uploads and ingests documents, so a separate sync
before deploy is optional. Searchability may lag a few minutes after sync or deploy.
Error responses
Errors return JSON with an error string and the appropriate HTTP status:
{
"error": "question is required"
} | Status | Meaning | Common causes |
|---|---|---|
400 | Bad Request | Invalid JSON; missing question or filename; question exceeds the project max length; no documents ready for sync; deploy before rotate; S3 objects missing on confirm |
401 | Unauthorized | Missing or invalid JWT / API key |
403 | Forbidden | Origin not allowed for public chat; insufficient project role |
404 | Not Found | Project, document, key not found; unknown route (No route for METHOD path) |
409 | Conflict | User already belongs to another company; user already a company member; user already has a company (signup) |
502 | Bad Gateway | Chat request failed upstream (Bedrock or retrieval error) |
503 | Service Unavailable | RAG / knowledge base not enabled in this environment |
Health
/health Auth: none (public)
Liveness probe — no authentication required. Use for uptime monitoring and deploy smoke tests.
curl 'https://api.oprag.ai/health' Response
{
"status": "ok",
"service": "oprag-api",
"timestamp": "2026-06-09T12:00:00.000Z"
} Ready to ship?
Get started free