For developers
The client API
Every deployment exposes one versioned HTTP API under /api/v1:
a data plane to push documents into the knowledge base, and a
message plane to ask questions and get cited answers. Both are
authenticated by a Bearer key you create in the admin console.
https://assistant.yourcompany.com/api/v1.
There is no Naxis-hosted API — your data never leaves your instance.
Two keys, two jobs
The API is surfaced as two catalog cards, each with its own key.
Create them under Documents → Add a source → API (the ingest key)
and Chat channels → Add a channel → API (the message key). A key
is a Bearer secret shown once at creation; it starts with nx_sk_.
| Card | Key authorises | Answers as |
|---|---|---|
| API source | the /ingest/* endpoints | — |
| API channel | the /messages* and /conversations* endpoints |
a guest at the channel's groups, or a specific user for a per-user key |
Authenticate every request with the header:
Authorization: Bearer nx_sk_…
Ingesting documents
Push a document by a stable external_id of your choosing — your
record id, a file path, anything unique within the source. Re-pushing the same
id replaces the document; the sweep re-indexes it in the background (responses
are 202 Accepted with a job id).
Create or replace one document
POST /api/v1/ingest/documents
Content-Type: application/json
{
"external_id": "crm/deal/8842",
"title": "Acme renewal — terms",
"text": "# Renewal\nThe Acme contract renews on 2026-09-01 …",
"acl": ["grp:sales"],
"metadata": {"source_system": "hubspot"}
}
Provide exactly one of text (inline markdown/text/HTML)
or content_base64 (base64 bytes for PDF, DOCX and other binaries, up
to 50 MB). acl is a list of groups (grp:*); omit it and
the document inherits the source's own groups. PUT /ingest/documents/{external_id}
does the same, taking the id from the path.
Batch
POST /api/v1/ingest/documents/batch
{ "documents": [ { "external_id": "…", "text": "…" }, … ] }
Up to 100 documents per call.
Read, delete, sync, status
| Method & path | Does |
|---|---|
GET /ingest/documents | List pushed documents with indexing status (limit, offset, prefix). |
GET /ingest/documents/{external_id} | One document and its status. |
DELETE /ingest/documents/{external_id} | Tombstone it (the sweep removes it). ?purge=true erases immediately. |
POST /ingest/sync | Re-index this source's corpus now. |
GET /ingest/status | Store and indexing counts for this source. |
Asking questions
POST /api/v1/messages
Content-Type: application/json
{ "text": "When does the Acme contract renew?",
"end_user": "u-3391",
"conversation_id": null }
The answer is grounded in the documents the caller is allowed to see, and it cites the exact passages — or abstains when the knowledge base doesn't contain the answer, rather than guessing.
{
"text": "The Acme contract renews on 1 September 2026 [1].",
"abstained": false,
"error": false,
"conversation_id": "6f1c…",
"citations": [
{ "n": 1, "chunk_id": "…", "breadcrumb": "Acme renewal — terms › Renewal" }
]
}
end_user scopes conversation memory within the channel, so two of your
users don't share a thread. Pass the returned conversation_id back to
continue a multi-turn conversation. POST /messages/stream streams the
same result over Server-Sent Events (a terminal final event carries the
authoritative payload). A per-user key answers as its owner with the owner's own
document access; the shared channel key answers as a guest at the channel's groups.
Conversations
| Method & path | Does |
|---|---|
GET /conversations | The caller's conversations. |
GET /conversations/{id} | One conversation's messages and citations. |
DELETE /conversations/{id} | Erase a conversation. |
Limits & errors
| Status | Meaning |
|---|---|
202 | Ingest accepted; indexing runs in the background (carries a job id). |
400 | Malformed request (missing external_id, both/neither of text and content, empty question). |
401 | Missing or unknown Bearer key. |
403 | Corpus is at the plan limit (new documents refused; updates still pass). |
413 | Document over 50 MB, or request over 100 MB. |
423 | The assistant is temporarily unavailable — contact your administrator. |
429 | Message rate limit; slow down. |
503 | The answering service was briefly unavailable; the turn was not saved — retry. |
/api/v1/openapi.json — point your generator or Postman at it.