Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API Reference

Base URL: https://your-instance (all REST endpoints live under /v1).

Unless noted, endpoints require authentication via Authorization: Bearer <api-key>. See Authentication for roles. A machine-readable OpenAPI spec (all public endpoints except the OAuth, MCP and internal admin ones) is served at GET /v1/openapi.json.

All request and response bodies are JSON unless stated otherwise. Errors use the format described in the Error Reference.

Roles. Each endpoint lists the minimum role: read < write < admin. Endpoints marked “any key” accept any valid API key.

Health

No authentication.

EndpointDescription
GET /health/live200 if the process is alive
GET /health/ready200 if the database is reachable, otherwise 503
GET /health/index200 if the vector indexes exist, otherwise 503. Body: {"idx_chunks_embedding": "ok|missing", "idx_platform_chunks_embedding": "ok|missing"}

Knowledge Bases

Create Knowledge Base

POST /v1/knowledge-bases

Role: write.

{
  "name": "guidelines",
  "dimensions": 1024
}
FieldTypeNotes
namestringRequired, 1–200 characters
dimensionsintegerOptional, 1–4096, default 1024. Immutable after creation

Response 201: {"id": "<kb-uuid>"}

Errors: 403 knowledge_base_limit_reached (plan limit), 422 (validation).

List Knowledge Bases

GET /v1/knowledge-bases

Any key. Returns an array of knowledge bases. Sub-tenant keys only see their own.

Update Knowledge Base

PATCH /v1/knowledge-bases/{kb_id}

Role: write. Body may contain name and/or translation_config (see Translation Settings). Including dimensions is rejected with 422.

Response: 204.

List Documents in a Knowledge Base

GET /v1/knowledge-bases/{kb_id}/documents

Any key. Returns an array of documents. 404 if the knowledge base is not accessible to your key.

There is no endpoint to delete a knowledge base through the API; delete its documents individually or use the web portal / account deletion.

Documents

Ingest Document (JSON)

POST /v1/documents

Role: write. Rate limited per tenant.

{
  "knowledge_base_id": "uuid",
  "title": "Document Title",
  "content": "Full text content...",
  "anonymize": true,
  "tags": {"specialty": "cardiology"}
}
FieldTypeNotes
knowledge_base_idstring (uuid)Required
titlestringRequired, 1–500 characters
contentstringRequired, max 10 MB and the plan’s max document size
anonymizebooleanOptional. Defaults to the tenant’s anonymization setting
tagsobjectOptional metadata, filterable at query time via filters

Response 202: {"job_id": "<uuid>"}. Ingestion is asynchronous; poll Get Job.

The size of content counts against your storage quota (and the sub-tenant’s, if the knowledge base belongs to one); deleting the document frees it.

Errors: 400 invalid knowledge_base_id, 404 not_found, 413 (document_too_large, storage quota exceeded, or sub_tenant_storage_quota_exceeded), 402 document_limit_reached, 402 chunk_quota_exceeded, 422. Enterprise sub-tenants may also see 403 sub_tenant_document_limit_reached, 429 sub_tenant_chunk_quota_exceeded and 429 tenant_pool_quota_exceeded.

Upload Document (File)

POST /v1/documents/upload
Content-Type: multipart/form-data

Role: write. Rate limited per tenant. Maximum request size 55 MB.

PartNotes
fileRequired. Content type text/plain or application/pdf
metadataRequired JSON string. Must include knowledge_base_id
curl -X POST https://your-instance/v1/documents/upload \
  -H "Authorization: Bearer $MEDRAG_API_KEY" \
  -F 'file=@guideline.pdf;type=application/pdf' \
  -F 'metadata={"knowledge_base_id": "<kb-id>"}'

Response 202: {"job_id": "<uuid>"}.

Errors: 400 (missing file, invalid metadata), 404 not_found, 413 (document_too_large, storage quota exceeded, or sub_tenant_storage_quota_exceeded with current and limit when the knowledge base’s sub-tenant is over its storage quota), 402 (document/chunk limits), 422 (unsupported file type, pdf_extraction_failed, parse_timeout, content_too_large).

Get Document

GET /v1/documents/{id}

Any key. 404 not_found if it does not exist.

Download Original File

GET /v1/documents/{id}/download

Any key. Returns the stored original file (application/pdf or application/octet-stream). 404 if the document has no stored file.

Delete Document

DELETE /v1/documents/{id}

Role: write. Response: 204, or 404 not_found.

Get Job

GET /v1/jobs/{id}

Any key. Returns the status of an asynchronous job. job_type is ingestion, transcription or report_generation; status progresses from queued through processing to completed or failed (with a sanitized error):

{
  "id": "uuid",
  "tenant_id": "uuid",
  "document_id": "uuid",
  "knowledge_base_id": "uuid",
  "job_type": "ingestion",
  "status": "completed",
  "error": null,
  "total_chunks": 42,
  "processed_chunks": 42,
  "created_at": "2026-10-04T10:00:00Z",
  "completed_at": "2026-10-04T10:00:03Z"
}

Query

POST /v1/query

Role: read. Rate limited per tenant (see Rate Limits). Optionally send an X-User-Id header (max 256 characters) to attribute the query to an end user for per-user limits and preferences.

{
  "query": "blood pressure targets",
  "top_k": 5,
  "knowledge_base_ids": ["uuid"],
  "filters": {"tags.specialty": "cardiology", "created_after": "2025-01-01"},
  "metadata_filter": {},
  "source_language": "auto",
  "translate_response": false
}
FieldTypeNotes
querystringRequired, 1–4096 characters
top_kintegerOptional, 1–100, default 10
knowledge_base_idsstring[]Optional. Restrict to these knowledge bases
filtersobjectOptional. Keys: tags.<key>, created_after, created_before, document_title (string values)
metadata_filterobjectOptional. Metadata filter for platform corpora results
source_languagestringOptional. auto (default) or one of en, nl, fr, de, es, it, bg, ro
translate_responsebooleanOptional. Translate result content back to the query language. Not available on the Free plan

Response 200:

{
  "results": [
    {
      "content": "Blood pressure targets for adults...",
      "score": 0.87,
      "source": "tenant",
      "document_id": "uuid",
      "document_title": "Hypertension Guidelines",
      "chunk_id": "uuid",
      "knowledge_base_id": "uuid",
      "chunk_index": 3,
      "document_tags": {"specialty": "cardiology"}
    }
  ]
}

Results from your own documents have "source": "tenant" and the document fields above. Results from platform corpora carry source_record_id and metadata instead. When translation is in effect, a metadata object is added at the top level with translation_config_source and translation_latency_ms, and translated results include the original text in content_original.

Response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After.

Errors: 400 unsupported_language, 402 quota_exhausted (Free plan), 402 payment_required (suspended account), 403 (response translation on Free plan), 422, 429 rate_limit_exceeded / per_user_rate_limit_exceeded, 503 translation_unavailable.

Platform Corpora

List Corpora

GET /v1/corpora

Any key.

{
  "corpora": [
    {
      "slug": "pubmed",
      "name": "PubMed Abstracts",
      "license_info": "…",
      "requires_dua": true,
      "accepted": false,
      "accessible": true
    }
  ]
}

accessible reflects your plan; accepted whether your tenant has accepted the corpus’s Data Use Agreement.

Accept Data Use Agreement

POST /v1/corpora/{slug}/accept-dua

Role: admin. Response 200: {"status": "ok"}. 404 if the corpus does not exist, 403 if it is not available on your plan.

Translation

Role: read for translate endpoints. Supported languages: en, nl, fr, de, es, it, bg, ro.

Translate

POST /v1/translate
{"text": "Hypertension", "source": "en", "target": "nl"}

Response: {"translated_text": "…", "source": "en", "target": "nl", "latency_ms": 12.3}

Translate Batch

POST /v1/translate/batch
{"texts": ["Hypertension", "Diabetes"], "source": "en", "target": "nl"}

1–100 texts per request. Response: {"translations": ["…", "…"], "source": "en", "target": "nl", "latency_ms": 20.1}

Detect Language

POST /v1/detect

Any key. Body: {"text": "…"}. Response: {"language": "nl", "confidence": 0.973}

Translation Health and Languages

EndpointDescription
GET /v1/translation/health{"status": "healthy|degraded|disabled", "models_loaded": n, "models_total": n, "models": [{"source", "target", "status"}]}
GET /v1/translation/languagesArray of supported {"source", "target"} pairs

Translation errors: 400 (text_too_long, invalid_batch_size, unsupported_language_pair), 503 translation_unavailable, 500 translation_failed.

Translation Settings

Translation configuration object (all fields optional):

{
  "query_translation": "auto",
  "response_translation": "on_request",
  "preferred_language": "nl",
  "fallback_behaviour": "passthrough"
}
FieldValues
query_translationauto, never
response_translationalways, on_request, never
fallback_behaviourpassthrough, error
EndpointRoleDescription
GET /v1/tenant/settingsadminReturns {"translation_config": {…}}
PATCH /v1/tenant/settingsadminBody {"translation_config": {…}}. The Free plan cannot set response_translation to always (403 free_tier_restriction)
PATCH /v1/sub-tenants/{id}/users/{user_id}/preferencesadminPer-user preferences, same body. Enterprise only (403 enterprise_only)

API Keys

Create API Key

POST /v1/auth/keys

Role: admin.

{"name": "ci-key", "role": "read"}

role must be read, write or admin. Response 201: {"key": "medrag_sk_…", "id": "<uuid>"}. The key is shown only once.

Revoke API Key

DELETE /v1/auth/keys/{id}

Role: admin. Response: 204.

Usage and Billing

Get Current Usage

GET /v1/usage

Any key.

{
  "chunks": {"used": 120, "limit": 5000, "percent": 2.4},
  "documents": {"used": 3, "limit": 50, "percent": 6.0},
  "storage_bytes": {"used": 10240, "limit": 52428800, "percent": 0.0},
  "knowledge_bases": {"used": 1, "limit": 1},
  "queries_this_period": {"used": 10, "limit": 1000, "percent": 1.0},
  "query_rate_limit_per_min": 10
}

Billing Usage

GET /v1/billing/usage

Role: admin. Usage over the last 30 days plus current-period counters:

{
  "plan_type": "standard",
  "included_queries": 50000,
  "total_requests": 1234,
  "total_input_tokens": 0,
  "total_output_tokens": 0,
  "total_cost_microcents": 0,
  "query_count": 1234,
  "ingestion_chunks": 560,
  "overage_queries": 0,
  "overage_cost_microcents": 0
}

Billing Events

GET /v1/billing/events

Role: admin. Currently always returns an empty array.

Plan Changes

Role: admin for all. Plans: free, payg, standard, enterprise. These return 503 billing_not_available when billing is not enabled on the instance.

EndpointBodyResponse
POST /v1/billing/upgrade{"plan": "standard"}{"status": "upgraded", "plan": "standard", "prorated_queries": n}
POST /v1/billing/downgrade{"plan": "free"}{"status": "scheduled", "plan": "free"} — applied at the end of the period
POST /v1/billing/cancel—{"status": "cancellation_scheduled"}
DELETE /v1/billing/cancel—{"status": "cancellation_retracted"}, or 404 no_pending_cancellation
POST /v1/billing/interval{"billing_interval": "monthly|annual"}{"status": …, "billing_interval": …}
POST /v1/billing/renew—Renews an annual plan; 409 not_annual_plan otherwise

Errors: 422 invalid_plan, 409 (already_on_plan, use_downgrade_endpoint, billing_details_required, cancellation_pending, already_on_free), 422 exceeds_target_plan_limits (downgrade blocked because current usage exceeds the target plan).

Data Processing Agreement

EndpointRoleDescription
GET /v1/dpa/statusany key{"compliant": bool, "current_version": n, "accepted_version": n|null}
POST /v1/dpa/acceptadminBody {"version": n}. Optional X-Accepted-By header records who accepted. Response {"status": "accepted", "dpa_version": n}

When your tenant has not accepted the current DPA version, API responses carry the header X-DPA-Action-Required: DPA re-acceptance required.

Account

Role: admin.

EndpointDescription
POST /v1/account/exportExports all account data. Returns download_url (valid for expires_in_seconds: 86400) plus account, knowledge_bases, documents, usage_history
DELETE /v1/accountDeletes the account and all data. Requires header X-Confirm-Delete: DELETE_MY_ACCOUNT. Returns 202

Enterprise: Sub-Tenants

Requires the Enterprise plan and an admin key that is not itself scoped to a sub-tenant (403 enterprise_plan_required, 403 sub_tenant_keys_cannot_manage_sub_tenants).

Sub-Tenants

EndpointDescription
POST /v1/sub-tenantsCreate. Returns 201 (or 200 with the existing record if external_id already exists)
GET /v1/sub-tenantsList
GET /v1/sub-tenants/{id}Get one
PATCH /v1/sub-tenants/{id}Update name and/or limits
DELETE /v1/sub-tenants/{id}Delete. Returns 204

Create body:

{
  "name": "Clinic A",
  "external_id": "clinic-a",
  "max_total_chunks": 100000,
  "max_knowledge_bases": 5,
  "max_documents": 1000,
  "max_document_size_bytes": 26214400,
  "query_rate_limit_per_min": 100,
  "included_queries_per_period": 10000,
  "storage_quota_bytes": 1073741824
}

Only name is required (1–200 characters); every other field is optional. Sub-tenant limits are enforced inside the parent tenant’s plan limits.

Sub-Tenant API Keys

EndpointDescription
POST /v1/sub-tenants/{id}/api-keysBody {"role": "read|write"}. Returns 201 {"key", "role", "sub_tenant_id"}
GET /v1/sub-tenants/{id}/api-keysList keys
DELETE /v1/sub-tenants/{id}/api-keys/{key_id}Revoke. Returns 204

Keys created here only see knowledge bases and documents of that sub-tenant.

Sub-Tenant Usage

EndpointDescription
GET /v1/sub-tenants/{id}/usagechunks, documents, queries_this_period, storage_bytes (each {used, limit}; storage counts uploaded files and is freed when a document is deleted) and active_users
GET /v1/usage/breakdown{"sub_tenants": [{sub_tenant_id, name, chunks, queries_this_period, active_users}], "total_chunks": n}
GET /v1/usage/usersArray of {sub_tenant_id, name, active_users} for the current month

Add-on: Transcription and Reports

Requires the corresponding add-on on your plan (otherwise 403 {"error": "addon_not_enabled", "addon": "transcription|report_generation"}) and the feature to be enabled on the instance (503 scribe_api_not_available). Role: write. Both endpoints are asynchronous: they return a job_id and deliver the result to your callback_url.

Transcribe Audio

POST /v1/transcribe
Content-Type: multipart/form-data

Maximum request size 25 MB. Parts: audio (required), language, callback_url, callback_secret. Response 202: {"job_id": "<uuid>"}.

Errors: 400 (unsupported_language, audio_too_long with max_seconds, invalid_callback_url), 503 transcription_unavailable.

Generate Report

POST /v1/reports/generate
{
  "transcript": "…",
  "callback_url": "https://example.com/hook",
  "callback_secret": "…"
}

Response 202: {"job_id": "<uuid>"}.

Errors: 400 (empty transcript, transcript_too_long with max_chars, invalid_callback_url), 503 report_generation_unavailable.

OAuth and MCP

OAuth 2.1 endpoints (/oauth/token, /oauth/revoke, /oauth/register, /.well-known/oauth-*) and the MCP transport (/mcp/sse, /mcp/message) are documented in MCP Integration and Authentication.