Naxis Technologies Docs
Live demo

The built-in API cards

Messaging API — ask over HTTP

The Messaging API lets your own application ask the assistant over HTTP and get grounded, cited answers — the programmatic sibling of the website widget. Every answer is access-controlled and audited exactly like the web chat. This article is the complete reference.

Two kinds of key

Setup

  1. Chat channels → Messaging API/MCP: name it, and pick the guest access groups the shared key may answer from.
  2. For per-person access, open Users → Edit → Chat channels and Generate a key for each person; copy it from there.
  3. Send the key in an Authorization: Bearer header. A messaging key can never ingest.

Endpoints

Message fields

textThe question, in any language.
end_userOptional caller id (1–128 chars: letters, digits, . _ : -, starting alphanumeric). With the shared channel key it keeps each end user's conversation memory separate; with a personal key it is ignored — the key already is the person.
conversation_idPass the id from a previous answer to continue that conversation.

The answer

Responses carry the answer text, abstained (true when the honest answer was “not in the knowledge base”), conversation_id, and citations — the numbered sources behind the text, each with its passage id, breadcrumb and source location. Personal-key conversations are the same ones the person sees in the web chat.

Example

A single question, in curl:

curl -X POST <base>/api/v1/messages \
  -H "Authorization: Bearer <key>" \
  -H "Content-Type: application/json" \
  -d '{"text":"What is the refund window?",
       "end_user":"u-4471"}'

The same call in Python, with error handling:

import requests

resp = requests.post(
    "<base>/api/v1/messages",
    headers={"Authorization": "Bearer <key>"},
    json={"text": "What is the refund window?", "end_user": "u-4471"},
)

if resp.status_code == 429:
    print("rate limited — slow down")
elif not resp.ok:
    # error bodies are {"detail": "..."}
    print(resp.status_code, resp.json().get("detail"))
else:
    data = resp.json()
    if data["abstained"]:
        print("not in the knowledge base")
    else:
        print(data["text"])
        for c in data["citations"]:
            print(f"[{c['n']}] {c['breadcrumb']}")

And in JavaScript, using fetch on Node 18 or later:

const resp = await fetch("<base>/api/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <key>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ text: "What is the refund window?", end_user: "u-4471" }),
});

const data = await resp.json();
if (resp.status === 429) {
  console.error("rate limited — slow down");
} else if (!resp.ok) {
  // error bodies are { detail: "..." }
  console.error(resp.status, data.detail);
} else if (data.abstained) {
  console.log("not in the knowledge base");
} else {
  console.log(data.text);
  for (const c of data.citations) console.log(`[${c.n}] ${c.breadcrumb}`);
}

Behaviour worth knowing

Machine-readable spec for Postman/codegen: /api/v1/openapi.json.

Was this page helpful?
Was this page helpful? Sign in with Google Sign in to tell us — or leave a comment.

Last updated 20 Sep 2026