Introducing Naad v1

Developers

Developer hubDocumentationQuickstartModelsAudio & Voice APISpeech-to-SpeechAuthenticationError referenceSolutions

Resources

BlogSystem statusDesktop appsPricingSign inSign up

Knowledge Bases

Host your business knowledge on Oogam and ground voice agents on it — no tool call, no client-side orchestration. Upload documents once; the platform extracts the text and compiles it into the grounding context the model reads, so the agent answers from your facts during live calls. The compilation happens on the platform at set_context time — the model needs no retrieval tool, which is why this works with naad-sts-v1 today even while function calling is still in preview.

Endpoints

MethodPathPurpose
POST/kbCreate → {"kb_id": "kb_…"}
GET/kbList, with document counts
GET/kb/{kb_id}Detail, including per-document status
DELETE/kb/{kb_id}Delete (documents and stored files included)
POST/kb/{kb_id}/documentsUpload — multipart file, {"url"}, or {"text"}
GET/kb/{kb_id}/documentsList with ingestion status
GET/kb/{kb_id}/documents/{doc_id}Single-document status (the poll target)
PUT/kb/{kb_id}/documents/{doc_id}Replace content in place — same doc_id, same compile order; body shapes as upload. Prefer this over delete + re-add when a document changes.
DELETE/kb/{kb_id}/documents/{doc_id}Remove

Detecting drift

Every ready document carries a content_hash (sha256 of its extracted text) and the knowledge base a combined kb_hash. The realtime context_ack reports the same kb_hash, so you can verify per session that the agent is grounded on your current content: hash your source, compare with the ack. The hash covers the source text — a knowledge base that is merely too big to fit whole reports truncation separately (kb_chars, kb_status), so "stale" and "didn't fit" can never be confused. When a document changes, replace it with PUT rather than delete + add: the doc_id and compile order stay stable.

Access & billing

Knowledge bases ship with the voice product: your key needs the naad permission and must belong to a workspace (org). CRUD operations are never billed — you only pay for the voice calls that use the knowledge. A key without the product gets 403 insufficient_permissions; a key with no workspace gets 403 org_required.

Create → ingest → poll

Ingestion is asynchronous: uploads return 202 with status pending, then move to ready or failed (with a human-readable error). Accepted sources: PDF, DOCX, TXT, MD, URL, raw text. Plain text is usually ready by the time the 202 lands; files and URLs within a few seconds.

bash
# 1. Create
curl -X POST https://platform.oogam.ai/v1/kb \
  -H "Authorization: Bearer $OOGAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Sharma Clinic", "description": "Hours, fees, address"}'
# → {"kb_id": "kb_37bd2418dd25431c9762", ...}

# 2. Add documents — a file…
curl -X POST https://platform.oogam.ai/v1/kb/kb_37bd…/documents \
  -H "Authorization: Bearer $OOGAM_API_KEY" \
  -F "file=@pricelist.pdf"
# → 202 {"doc_id": "doc_…", "status": "pending"}

# …or a page…
curl -X POST https://platform.oogam.ai/v1/kb/kb_37bd…/documents \
  -H "Authorization: Bearer $OOGAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://sharmaclinic.example/faq"}'

# …or plain text
curl -X POST https://platform.oogam.ai/v1/kb/kb_37bd…/documents \
  -H "Authorization: Bearer $OOGAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Open Mon–Sat 9am–7pm. Sunday closed.", "name": "Hours"}'

# 3. Poll until every document is ready
curl https://platform.oogam.ai/v1/kb/kb_37bd… -H "Authorization: Bearer $OOGAM_API_KEY"

Adding documents

POST /kb/{kb_id}/documents takes exactly one of three shapes, chosen by content type:

SourceHow to sendNotes
Filemultipart/form-data with a file partPDF, DOCX, TXT, MD. Up to 10 MB. Missing part → 400 missing_file; wrong type → 400 unsupported_file_type.
URLJSON {"url": "https://…", "name"?: "…"}The page is fetched and its text extracted. Must be a public http(s) URL — private/internal addresses are refused. Invalid → 400 invalid_url.
TextJSON {"text": "…", "name"?: "…"}Up to 200,000 characters. Ready almost immediately. Over the cap → 400 input_too_long.

Each returns 202 {"doc_id": "doc_…", "status": "pending"}. Poll the document (or the KB detail) until status is ready. Creating a KB POST /kb {"name", "description"?} — requires a 1–120 character name and returns 201 {"kb_id", "name", "created_at"}.

Object fields

A knowledge base, from GET /kb/{kb_id}:

FieldDescription
kb_idStable id (kb_…).
name / descriptionAs set on create.
created_atISO 8601 timestamp.
document_count / documents_readyPresent in the list view — totals for quick status.
documentsPresent in the detail view — the array of document objects below.

A document, from the documents list or single-document poll:

FieldDescription
doc_idStable id (doc_…).
nameFile name, page host, or your supplied name.
source_typefile, url, or text.
statuspendingready | failed.
errorPresent only when status is failed — a human-readable reason.
bytes / charsSource size and extracted-text length.
created_atISO 8601 timestamp.
json
{
  "kb_id": "kb_37bd2418dd25431c9762",
  "name": "Sharma Clinic",
  "description": "Hours, fees, address",
  "created_at": "2026-08-22T09:25:20.405Z",
  "kb_hash": "3568f557d16c…",
  "documents": [
    { "doc_id": "doc_5180…", "name": "Hours", "source_type": "text",
      "status": "ready", "bytes": 54, "chars": 54,
      "content_hash": "a0c20222921f…",
      "created_at": "2026-08-22T09:25:31.014Z" },
    { "doc_id": "doc_95b4…", "name": "pricelist.pdf", "source_type": "file",
      "status": "failed", "error": "No readable text found (is it a scan?).",
      "bytes": 20481, "chars": 0,
      "created_at": "2026-08-22T09:25:44.221Z" }
  ]
}

DELETE on a KB or a document returns {"kb_id" | "doc_id": "…", "deleted": true} and removes the stored files too.

Grounding a live call

Pass the kb_id in set_context on the realtime WebSocket. The platform compiles the knowledge base's ready documents into the grounding context that answers business questions during the call — the knowledge is authoritative, and the agent says it doesn't have a detail rather than inventing one. The compiled context is capped at about 6,000 characters, so the highest-value documents come first.

WebSocket
// Ground a Live talk session on your knowledge base:
ws.send(JSON.stringify({
  type: "set_context",
  kb_id: "kb_37bd2418dd25431c9762",
  system: SYSTEM_PROMPT,          // persona and rules, as usual
}));

Verify it loaded. The context_ack that comes back reports exactly what was compiled — assert kb_chars > 0 in your integration test rather than trusting that the attach worked:

json
{"type":"context_ack","kb_id":"kb_…","chars":239,
 "kb_documents":1,"kb_chars":5005,"kb_status":"loaded","ok":true}

An unknown or another workspace's kb_id is refused at set_context with kb_not_found, and a knowledge base whose documents are not yet ready with kb_empty — the session is never left silently ungrounded. If the compiled text had to be trimmed to fit alongside your own prompt, kb_status is loaded_truncated.

Limits

LimitValue
Knowledge bases per account20
Documents per knowledge base50
File size10 MB
Extracted text per document200,000 characters

About tenant

tenant is your workspace (organization) id — the same scope that owns your API keys, knowledge bases and cloned voices. It is provisioned automatically with your account; you never create one explicitly. On the realtime socket it may appear as a ?tenant= query parameter (the dashboard sets it for you) and in voice_rejected errors when a voice belongs to a different workspace. Your own tenant value is shown on each of your cloned voices in GET /voices.

Endpoint errors

StatusCodeMeaning
400invalid_requestKB name missing or not 1–120 characters.
400kb_limit_reached / kb_document_limit_reachedAccount limits (20 KBs, 50 docs) reached.
400missing_file / missing_inputNo file part, and no url/text either.
400unsupported_file_type / file_too_large / invalid_url / input_too_longDocument validation failures (type, 10 MB, URL, 200k chars).
403insufficient_permissions / org_requiredKey lacks the naad product, or is not attached to a workspace.
404not_foundUnknown (or another workspace's) kb_id / doc_id.