Skip to content

Agent API

Call one of your agents from your own server. You send a question, we answer it from that agent’s documents and name the documents the answer came from.

We will not break a working integration without telling you first.

Server-side only

This endpoint sends no CORS headers, so a browser cannot call it. Keep your key on your server — a key in frontend code is readable by anyone who opens devtools, and can be used against your usage from anywhere.

Getting a key

Open an agent in the dashboard and create a key under API access. Keys look like nsk_live_… and belong to one agent — a key for your support agent cannot query your legal agent.

The key is shown once. We store a hash of it, so there is no way to display it again. If you lose it, revoke it and create another.

You can hold several keys per agent and revoke them one at a time, which is what makes rotation possible with no downtime: create the new key, deploy it, then revoke the old one.

Available on paid plans. Owners and admins can manage keys.

What we store

Nothing from the conversation. No messages, no questions, no data about the person asking. Your users are your users.

We record one row per call for billing and support: which key, which agent, how many tokens, whether it succeeded, and when. That is for your invoice, not for the content.

This is why history exists in the request below — we have no memory of the previous turn, so if you want follow-up questions to work, you send the recent turns yourself.

Making a request

POST https://api.nenosource.com/api/v1/agents/{agentId}/chat
Authorization: Bearer nsk_live_...
Content-Type: application/json
{
  "message": "What is our refund window?",
  "history": [
    { "role": "user", "content": "Hi" },
    { "role": "assistant", "content": "How can I help?" }
  ]
}
FieldTypeNotes
messagestring, requiredThe question. 2–4000 characters.
historyarray, optionalRecent turns from your own chat, oldest first. Roles are “user” or “assistant” only.
conversationIdstring, reservedAccepted and ignored today. Declared now so we can add server-side conversations later without breaking you.

History rules

History tokens count toward your plan’s usage. Everything you send is re-read by the model on every request, so a long history makes every call cost more. Send the last few turns, not the whole conversation.

Too much history is rejected, not trimmed. Over 20 turns, or roughly 4000 tokens, answers 400. We do not quietly drop the rest — a request that silently stopped reading half its input would produce answers you could not explain.

role: "system"is rejected. The agent’s own instructions are configured in the dashboard and cannot be overridden per request.

The response

{
  "success": true,
  "data": {
    "agentId": "018f8c1f-...",
    "answer": "Refunds are accepted within 30 days of purchase.",
    "sources": ["refund-policy.pdf"]
  }
}
FieldTypeNotes
agentIdstringThe agent that answered. Echoed so one handler can serve several agents.
answerstringPlain markdown, ready to show your user. No citation markers.
sourcesstring[]Names of the documents the answer was built from, best match first, no duplicates. Empty when nothing matched.

The answer is prose, not annotated text. Internally the model is asked to cite each claim, which is what keeps it inside your documents rather than answering from its own training — but those markers are stripped before the answer reaches you. Render it as-is.

sources lists every document the answer drew on, not only the ones the model happened to mention. If it is empty, nothing in your indexed documents matched the question — check the file finished indexing.

Errors

Failures use the same envelope as every response: { "success": false, "error": { "code", "message" } }. Branch on code, never on message — the codes are stable and the wording is not.

StatusCodeWhat happened
400VALIDATION_FAILEDMalformed body, a system role in history, or history over the limit.
401UNAUTHENTICATEDMissing, malformed, unknown or revoked key.
402LIMIT_EXCEEDEDThe workspace is out of monthly usage, or its plan does not include the API.
404NOT_FOUNDNo such agent — including when the key belongs to a different one.
409CONFLICTThe agent is archived and cannot answer.
429RATE_LIMITEDToo many requests for this key. Honour Retry-After.
503SERVICE_UNAVAILABLETemporarily off. Retry with backoff rather than failing permanently.

Rate limits

Each key is limited independently, so one runaway integration cannot exhaust another. The default is 60 requests per minute per key; a 429 carries Retry-After.

Separately, your plan’s monthly usage applies. Running out answers 402, which retrying will not fix — it means upgrade or wait for the period to reset.

Not available yet

Browser-safe publishable keys, session tokens for a website widget, domain allow-lists, and conversations stored on our side. Those arrive together with the embeddable widget.

Until then, conversationId is accepted and ignored, so adding it later will not break anything you write today.

CookiesWe use essential cookies to keep you signed in and remember your preferences. With your OK, we'd also use analytics cookies to see which pages and features get used — never your documents or messages. Privacy Policy