The built-in API cards
Recall — ask in one call, choosing where to look
Recall is the asking call built for programs: your own application, an automation, or an AI agent that already knows it is asking. One request, no conversation to keep, and the reply carries the answer together with the places it was found — up to twenty sources, each naming the document, the passage and the connected source it lives in. It runs under the same access rules and audit trail as every other way of asking: a caller only ever gets what its key may see.
Where to look
The one thing recall adds to a question is where. Leave it out and Naxis Assistant looks across everything the key may see; name sources and it looks only there. Each entry is one of:
- a source's name, exactly as shown on its card under Documents — "Contracts drive"
- a source kind, meaning every source of that kind — internal, google_drive, notion, confluence, api, folder and the other kind names from the catalog
- a source id (shown on the source's card, or by list_sources over MCP)
- a folder of the internal docs — "internal:handbook/onboarding", or {"source": "internal", "path": "handbook/onboarding"}
Entries add up: ["internal", "Contracts drive"] looks in both. A name nothing matches is refused with the list of what this deployment does have, rather than silently searching nothing.
The reply
| text / summary | The grounded answer with its [n] citations, and its one-line summary. When nothing on record speaks to the question, abstained is true and text says so. |
|---|---|
| sources | At most limit (default 20) entries: the cited ones first, wearing their n, then the rest of what was read, by rank. Each carries passage_id, document_id, title, source_uri, source {source_id, kind, name}, breadcrumb, an excerpt, the document's date and a score. |
| where | What the where you sent resolved to — each source's id, kind and name, and the folder where one was given. |
| error | true when answering itself failed (the HTTP status is then 503); check it alongside abstained. |
Over HTTP
POST /api/v1/recall, authenticated like a message: a Messaging API/MCP key — the channel's shared key, a person's own key, or an Admin key — in an Authorization: Bearer header.
| question | The question, in any language. |
|---|---|
| where | Optional — a list of the entries above, or a single one as a string. |
| limit | Optional — sources to return, 1 to 20 (default 20). |
| context | Optional — earlier turns the question follows on from, as [{"role": "user", "content": "…"}, {"role": "assistant", "content": "…"}]. Nothing is stored between calls; pass what matters. |
| end_user | Optional — with the shared channel key, whose question this is, for the audit trail and the rate limit. |
One call, in curl:
curl -X POST <base>/api/v1/recall \
-H "Authorization: Bearer <key>" \
-H "Content-Type: application/json" \
-d '{"question":"What did we decide about the DC-2 penalty?",
"where":["internal:decisions","Contracts drive"],
"limit":10}'
The same call in Python, reading the sources back:
import requests
resp = requests.post(
"<base>/api/v1/recall",
headers={"Authorization": "Bearer <key>"},
json={
"question": "What did we decide about the DC-2 penalty?",
"where": ["internal:decisions", "Contracts drive"],
"limit": 10,
},
)
if resp.status_code == 400:
# a where naming nothing: the detail lists what exists
print(resp.json()["detail"])
elif not resp.ok:
print(resp.status_code, resp.json().get("detail"))
else:
data = resp.json()
print(data["summary"] or data["text"])
for s in data["sources"]:
mark = f"[{s['n']}]" if s["cited"] else " - "
print(mark, s["title"], "—", s["source"]["name"], s["source_uri"])
And in JavaScript, using fetch on Node 18 or later:
const resp = await fetch("<base>/api/v1/recall", {
method: "POST",
headers: {
"Authorization": "Bearer <key>",
"Content-Type": "application/json",
},
body: JSON.stringify({
question: "What did we decide about the DC-2 penalty?",
where: ["internal:decisions", "Contracts drive"],
limit: 10,
}),
});
const data = await resp.json();
if (!resp.ok) {
// error bodies are { detail: "..." }
console.error(resp.status, data.detail);
} else {
console.log(data.summary || data.text);
for (const s of data.sources) console.log(s.cited ? `[${s.n}]` : " - ", s.title, s.source.name);
}
Over MCP
The recall tool takes the same fields — question, where, limit, context, end_user — and returns the answer as text plus the structured reply described above. It sits next to ask on every Messaging key and on the Admin key: ask is for a person's conversation, recall for a program's question.
curl -X POST https://YOUR-DEPLOYMENT/mcp \
-H "Authorization: Bearer nx_ak_YOURKEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"recall",
"arguments":{"question":"What did we decide about the DC-2 penalty?",
"where":["internal:decisions"],"limit":5}}}'
Behaviour worth knowing
- Rate limit: 60 calls per minute per channel and end user (429 when exceeded) — the same allowance as messages.
- Nothing is remembered between calls; pass context yourself when a question follows on from another.
- Every call is audited with the sources it read and cited and the where it ran under, like every question asked anywhere else.
- The internal docs are the natural place for what an agent writes down — a decision, a summary, a note to its future self — and recall with where set to internal (or to one of its folders) reads it back. See Internal docs.
Machine-readable spec for Postman/codegen: /api/v1/openapi.json.
Last updated 17 Sep 2026