API reference
The AhoosAI API serves the Nimbus 2 Apex model in the format of OpenAI's Chat Completions API. Existing OpenAI client libraries work with it once the base URL and the key are changed.
Base URL
https://ahoos-ai.site/services/api/v1
| Method | Path | Purpose |
|---|---|---|
GET | /models | Lists the available models. |
POST | /chat/completions | Generates a response to a conversation. |
Authentication
Every request to /chat/completions must carry an API key in the Authorization header:
Authorization: Bearer nim_YOUR_KEY
Keys are created and revoked on the platform after signing in. A missing, unknown or revoked key is answered with status 401.
Example
With the official OpenAI library for Python:
from openai import OpenAI
client = OpenAI(base_url="https://ahoos-ai.site/services/api/v1", api_key="nim_YOUR_KEY")
response = client.chat.completions.create(
model="nimbus-2-apex",
messages=[{"role": "user", "content": "Explain recursion in two sentences."}],
extra_body={"thinking_level": 5},
)
print(response.choices[0].message.content)
Request
POST /chat/completions accepts a JSON body of at most 16 MB.
| Field | Type | Description |
|---|---|---|
messages | array | Required. The conversation. Roles: system, user, assistant, tool. The last message must be user or tool. Content is a string or an array of text parts. |
model | string | Optional. If given, it must be nimbus-2-apex. |
stream | boolean | Streams the response as server-sent events. Default false. |
max_tokens | integer | The maximum length of the answer, from 16 to 8,192 tokens. Default 4,096. max_completion_tokens is accepted as well. The reasoning has its own budget, set by the reasoning level. |
thinking_level | integer | Reasoning level, 1 to 20. Default 5. Higher levels reason longer before answering. |
reasoning_effort | string | An alternative to thinking_level: minimal (1), low (3), medium (6) or high (12). |
temperature_dial | integer | Temperature, 1 to 10. Default 5. Lower values give more predictable answers. |
temperature | number | An alternative to temperature_dial: the value is multiplied by 5 and rounded (1.0 becomes 5). |
tools | array | Functions the model may call, in OpenAI's format. See Tools. |
tool_choice | string or object | auto (default), none, required, or {"type": "function", "function": {"name": "..."}}. |
nimbus_tools | array | Tools that run on AhoosAI's side: web_search, fetch_url. See Web search. |
web_search_options | object | Turns on web search, as in OpenAI's API. Its contents are not used. |
Other fields of OpenAI's format are accepted and ignored. Audio and files other than images are not supported.
Response
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "nimbus-2-apex",
"choices": [{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "The answer.",
"reasoning_content": "The reasoning that preceded it."
}
}],
"usage": {"prompt_tokens": 120, "completion_tokens": 310, "total_tokens": 430},
"nimbus": {"thinking_level": 5, "temperature": 5, "think_words": 160, "forced_close": false, "tokens_per_second": 28.4}
}
reasoning_contentholds the model's reasoning;contentholds the answer.finish_reasonisstop,length(the answer reachedmax_tokensor the context limit) ortool_calls.nimbus.forced_closeistruewhen the reasoning reached the ceiling of its level and was closed.
Streaming
With "stream": true the response is a sequence of server-sent events, each a line data: {...}:
choices[0].delta.reasoning_content: the next part of the reasoning.choices[0].delta.content: the next part of the answer.choices[0].delta.tool_calls: a tool call, sent complete in one event.- The last event carries
finish_reason,usageandnimbus; the stream then ends withdata: [DONE].
An error during the stream is sent as data: {"error": {"message": "...", "type": "..."}}.
Tools
Tools follow OpenAI's function-calling format. When the model decides to use a tool, the response ends with finish_reason: "tool_calls" and one call in message.tool_calls. Run the function, add the assistant message and a tool message with the result to the conversation, and send it again:
{"role": "tool", "tool_call_id": "call_...", "content": "the function's result"}
The arguments of every call match the parameter schema of the tool. At most one call is returned per response.
Images
A user message may include images as OpenAI's image_url parts, given as a data: URL (PNG, JPEG, WebP or GIF) or an https address:
{"role": "user", "content": [
{"type": "text", "text": "What does this chart show?"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}}
]}
The model reads text only. Each image is first read by AhoosAI's image module, apex-imagexo-v1, which turns its text (read by OCR, in English and Persian) and its shapes (position, size and colour) into an XML scene; the model answers from that scene. It reads documents, screenshots, tables, forms, charts and diagrams well; it does not see the content of photographs, such as faces or objects.
- Up to 4 images per request, each up to 8 MB.
- The scenes of the last message's images are returned in
nimbus.images. Send them as text in later turns instead of the image, so the image is not read again.
Agents and tools
When a request carries your own tools, the model works as an agent: at every step it either calls one of your tools or replies, and the call's arguments follow the tool's parameter schema. To help it choose, tools with common names for writing, editing and reading files, listing files and running commands (for example Write, Edit, Read, Glob, Bash) are pointed out to it, and a project folder named in your system message (such as Primary working directory: ...) is given to it as the place for files. Keep the list of tools to what the task needs: a long list costs context and makes the right choice harder.
Web search
"nimbus_tools": ["web_search", "fetch_url"] (or web_search_options) lets the model search the web and read pages before it answers. These tools run on AhoosAI's servers; their calls are not returned to you, and the answer continues with their results. An answer may use up to six such steps.
- In a stream, each step is reported in a
nimbus_toolfield:{"id", "name", "arguments", "status"}, wherestatusisrunning,doneorerror. A finished search also lists itsresults(title, url, snippet). - In a non-streamed response, the finished steps are listed in
nimbus.tools.
Search queries are sent to public search engines, and pages are fetched from their own sites.
Errors
Errors use OpenAI's format: {"error": {"message": "...", "type": "..."}}.
| Status | Type | Meaning |
|---|---|---|
| 400 | invalid_request_error | The body is not valid JSON, has no messages, or does not end with a user or tool message. |
| 401 | authentication_error | The key is missing, unknown or revoked. |
| 404 | invalid_request_error | Unknown endpoint or model. |
| 405 | invalid_request_error | The method is not allowed. |
| 413 | invalid_request_error | The body is larger than 16 MB. |
| 429 | rate_limit_error | The key's limit for the period is used up. The error includes used, limit and period. |
| 502, 503 | engine_error, engine_unavailable | The model could not answer. Retry later. |
Context and timing
- A request may use up to 40,960 tokens in total: the conversation, the tool definitions, the reasoning and the answer. When it is longer, the descriptions of the tools are shortened first and then the oldest exchanges are left out; if the last exchange alone does not fit, the request fails.
- The model starts on demand. After a period without requests, the first response can take up to two minutes.
- Requests are answered one at a time; others wait for their turn.
- A long request can take a minute before its first token. While a streamed response waits, the server sends comment lines (
: keepalive) every few seconds, which SSE clients ignore.