Skip to article
NEXUSDocs
Documentation/Developers
Operator reference

Send a Message to Nexus

Sending messages programmatically to Nexus

Before you begin

This reference describes the underlying platform. Use a Nexus school release with its school membership, class policy, and cost controls. Installing a base engine alone does not add those controls.

/chat/send-message and /chat/send-message-simple-api have been removed. Use this API instead.

The /chat/send-chat-message API is used to send a message to Nexus. It is the same API that the Nexus frontend uses to send and receive messages. You have the option of receiving a streaming response or the complete response as a string.

This guide was explain all of the parameters you can pass in to the API and provide a code sample.

Request Parameters#

ParameterDescription
messageThe user message to send to the Agent.
llm_overridePass an object to override the default LLM settings for this request. If None, you will get the default Nexus behavior. You can pass or exclude any of the following fields: • model_configuration_id - the exact model configuration to use. Preferred over the name-based fields, since provider display names are not unique • model_providermodel_versiontemperaturedisplay_name - label shown for the model in the UI; falls back to model_version If you pass an invalid configuration (e.g., specifying claude-sonnet-4.5 when the default model_provider is OpenAI), your request will fail.
llm_overridesTwo or three llm_override objects to run in parallel (multi-model mode), one per model. Requires stream=true. Sending more than one entry with stream=false fails with 400 {"error_code": "INVALID_INPUT"}. A list with a single entry is ignored. use llm_override for an ordinary single-model request.
allowed_tool_idsAgents are created with a set of Actions they are allowed to invoke. You can further configure this set for your immediate interaction using this parameter. See the list of Actions and their IDs via the GET /tool endpoint. Pass in an empty list to disable all Actions. Pass in None to allow all the Actions which are configured for the Agent.
forced_tool_idForce the Agent to use a specific Action for this request. The Agent may run other Actions before returning its final response, but it will be guaranteed to use this one. Leave empty to let the Agent decide which Actions to use.
file_descriptorsA list of files to include along with your request. File IDs can be found via the POST /user/projects/file/upload and the GET /user/projects/file/{file_id} endpoints.
internal_search_filtersFilters to narrow down the internal search results used by the Agent. All filter arguments are optional and can be combined: • source_type - Source types like web, slack, google_drive, confluencedocument_set - The name of the document sets to search within • created_at_range / updated_at_range - An inclusive window, {"start": ..., "end": ...}, in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ. Either bound may be omitted to leave that side open; naive timestamps are treated as UTC • tags - A list of {"tag_key": ..., "tag_value": ...} objects Note: time_cutoff is still accepted as a deprecated alias for the start of updated_at_range.
deep_researchEnables Deep Research mode for this request. Note: This mode consumes significantly more tokens, so be careful accessing it via the API.
mcp_headersHeaders forwarded to MCP tool calls made while answering this message, e.g. {"Authorization": "Bearer <user_jwt>"}. Use this to pass end-user credentials through to MCP servers that require them.
parent_message_idThe ID of the parent message in the chat history (primary-key for the previous message in the chat history tree). If not passed in, your new message is assumed to be sequentially after the last message. Warning: If set to None, the chat history is reset and the new message is considered the first message in the chat history.
chat_session_idTo continue an existing conversation, pass in the chat session ID where the message should be sent. If left blank, a new chat session will be created according to chat_session_info.
chat_session_infoDetails about the chat session which will be used for all messages in the session. Fields can be left blank to use defaults. • persona_id - The ID of the Agent to use for the chat session • project_id - ID of a Project if the chat should be scoped to a Project • incognito - Start the session in incognito mode. The request is refused with an error when incognito is not available to the user, never silently downgraded to an ordinary chat • incognito_session_id - The session ID already used when uploading files, so the new session owns those files. Ignored unless incognito is true
streamIf true, responds with an SSE stream of individual packets (same set used for the Nexus UI). Fields like the Answer, reasoning tokens, and iterative Tool Calls need to be pieced together from streamed tokens.
include_citationsIf true, responses will include citations for the sources used to generate the answer.
additional_contextA string of extra context injected into the LLM call for this request. The context is passed to the model but is not stored in the database and will not appear in chat history.Use this to supply ephemeral, request-scoped information (e.g. the user's current page URL, session metadata, or any runtime context) without polluting the persistent conversation history.Pass null or omit the field to use no additional context.

Response Format#

Streaming Response#

Nexus returns various types of packets in the streaming response depending on the LLM's behavior.

See our streaming_models.py on GitHub for the complete list of packet types and their corresponding fields.

class StreamingType(Enum):
  """Enum defining all streaming packet types. This is the single source of truth for type strings."""

  SECTION_END = "section_end"
  STOP = "stop"
  TOP_LEVEL_BRANCHING = "top_level_branching"
  ERROR = "error"
  CHAT_HEARTBEAT = "chat_heartbeat"

  MESSAGE_START = "message_start"
  MESSAGE_DELTA = "message_delta"
  SEARCH_TOOL_START = "search_tool_start"
  SEARCH_TOOL_QUERIES_DELTA = "search_tool_queries_delta"
  SEARCH_TOOL_FILTER_DELTA = "search_tool_filter_delta"
  SEARCH_TOOL_DOCUMENTS_DELTA = "search_tool_documents_delta"
  OPEN_URL_START = "open_url_start"
  OPEN_URL_URLS = "open_url_urls"
  OPEN_URL_DOCUMENTS = "open_url_documents"
  IMAGE_GENERATION_START = "image_generation_start"
  IMAGE_GENERATION_HEARTBEAT = "image_generation_heartbeat"
  IMAGE_GENERATION_FINAL = "image_generation_final"
  PYTHON_TOOL_START = "python_tool_start"
  PYTHON_TOOL_DELTA = "python_tool_delta"
  CUSTOM_TOOL_START = "custom_tool_start"
  CUSTOM_TOOL_ARGS = "custom_tool_args"
  CUSTOM_TOOL_DELTA = "custom_tool_delta"
  FILE_READER_START = "file_reader_start"
  FILE_READER_RESULT = "file_reader_result"
  REASONING_START = "reasoning_start"
  REASONING_DELTA = "reasoning_delta"
  REASONING_DONE = "reasoning_done"
  CITATION_INFO = "citation_info"
  TOOL_CALL_DEBUG = "tool_call_debug"
  TOOL_CALL_ARGUMENT_DELTA = "tool_call_argument_delta"

  MEMORY_TOOL_START = "memory_tool_start"
  MEMORY_TOOL_DELTA = "memory_tool_delta"
  MEMORY_TOOL_NO_ACCESS = "memory_tool_no_access"

  DEEP_RESEARCH_PLAN_START = "deep_research_plan_start"
  DEEP_RESEARCH_PLAN_DELTA = "deep_research_plan_delta"
  RESEARCH_AGENT_START = "research_agent_start"
  INTERMEDIATE_REPORT_START = "intermediate_report_start"
  INTERMEDIATE_REPORT_DELTA = "intermediate_report_delta"
  INTERMEDIATE_REPORT_CITED_DOCS = "intermediate_report_cited_docs"

  CODING_AGENT_START = "coding_agent_start"
  CODING_AGENT_THINKING_DELTA = "coding_agent_thinking_delta"
  CODING_AGENT_FINAL = "coding_agent_final"

  BASH_TOOL_START = "bash_tool_start"
  BASH_TOOL_DELTA = "bash_tool_delta"

Non-streaming Response#

class ChatFullResponse(BaseModel):
  """Complete non-streaming response with all available data."""

  # Core response fields
  answer: str
  answer_citationless: str
  pre_answer_reasoning: str | None = None
  tool_calls: list[ToolCallResponse] = []

  # Documents & citations
  top_documents: list[SearchDoc]
  citation_info: list[CitationInfo]

  # Metadata
  message_id: int
  chat_session_id: UUID | None = None
  incognito: bool = False
  error_msg: str | None = None

Sample Request#

import requests

API_BASE_URL = "https://school.narb.cc/api"  # or your own domain
API_KEY = "YOUR_KEY_HERE"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(
    f"{API_BASE_URL}/chat/send-chat-message",
    headers=headers,
    json={
        "message": "What is Onyx?",
    }
)

data = response.json()
print("Answer:", data["answer"])
print("Message ID:", data["message_id"])
#!/bin/bash

API_BASE_URL="https://school.narb.cc/api"  # or your own domain
API_KEY="YOUR_KEY_HERE"

RESPONSE=$(curl -s -X POST "${API_BASE_URL}/chat/send-chat-message" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "What is Onyx?"
  }'
)

echo "Answer:" $(echo "$RESPONSE" | jq -r '.answer')
echo "Message ID:" $(echo "$RESPONSE" | jq -r '.message_id')

Next Steps#

Guide: Use the Ingestion API#

Use the lightweight ingestion API to index documents

Guide: Create a Connector#

Learn how to create and configure Connectors programmatically

NEXUS

Nexus helps students think, practice, and learn, with teachers guiding AI use.

[ Support ]

[ NARB TECHNOLOGY INC. ]

Nexus is a school AI platform by narb Technology Inc. · 16192 Coastal Hwy, Lewes, DE 19958

© 2026 narb Technology Inc.

Nexus

Nexus helps schools make room for questions, practice, and reflection — with teacher guidance in view.

[ Contact us through e-mail ]

© 2026 narb Technology Inc.

NEXUS

Nexus helps students think, practice, and learn, with teachers guiding AI use.

[ Support ]

[ NARB TECHNOLOGY INC. ]

Nexus is a school AI platform by narb Technology Inc.

© 2026 narb Technology Inc.