Search docs

Search docs, endpoints, errors

Core Models (LLM API)

apodex-1.1 and apodex-1.1-mini — direct, OpenAI-compatible access to the underlying language models, with no agent loop in between.

POST/v1/chat/completions
https://api.apodex.ai

Overview

Core models are the Apodex language models themselves, exposed over the standard OpenAI wire format — no planning loop, no web search, no tools running on our side. Point the official openai SDK at the base URL below and your existing code works unchanged. They share the /v1/chat/completions path with the deep research models but deliberately behave differently — read the comparison table before you switch.

Base URL
https://api.apodex.ai/v1
Authentication
Bearer API Key
Format
OpenAI-compatible

The same models are also reachable over the Anthropic protocol at POST /v1/messages, at identical prices — see Anthropic Messages API if your client already speaks that dialect (Anthropic SDKs, Claude Code).

Models

Two text-only models, both with a 262,144-token context window. Same API, same parameters — pick by capability and cost.

ModelsBest forParametersContext windowList price
Apodex 1.1apodex-1.1
Hard reasoning, long context, quality-critical work397B262,144in $0.30 · cached $0.030 · out $3.00
Apodex 1.1 Miniapodex-1.1-mini
High-throughput, latency- or cost-sensitive work35B262,144in $0.10 · cached $0.010 · out $1.00

/ 1M tokens

Both ids are also returned by GET /v1/models, together with their context_length and max_completion_tokens.

Quickstart

The endpoint is OpenAI-compatible: set base_url and your API key, and the official SDKs work as-is. Note that stream defaults to false here.

Headers

HeaderValueDescription
Authorization
Required
Bearer YOUR_API_KEYYour Apodex API key, sent as a bearer token.
Content-Type
Required
application/jsonAlways application/json.
X-Session-Id
Optional
<your-stable-conversation-key>Optional. A stable key for one logical conversation — sending the same value across turns significantly improves prefix cache hit rate (lower latency, lower cost). Omit it and the server derives a key from the request content.

Request

curl -X POST https://api.apodex.ai/v1/chat/completions \
  -H "Authorization: Bearer $APODEX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Session-Id: my-conversation-42" \
  -d '{
    "model": "apodex-1.1",
    "messages": [
      {"role": "user", "content": "Explain prefix caching in one paragraph."}
    ],
    "max_tokens": 512,
    "temperature": 0.7
  }'

Response

Non-Streaming
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1712345678,
  "model": "apodex-1.1",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "reasoning_content": "The user wants a one-paragraph explanation...",
        "content": "Prefix caching reuses..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 187,
    "total_tokens": 229,
    "prompt_tokens_details": { "cached_tokens": 32 }
  }
}

Supported parameters

Sampling parameters are passed through to the model natively — no rewriting, no silent clamping.

ParameterSupport
modelRequired. apodex-1.1 or apodex-1.1-mini.
messagesRequired. Standard OpenAI chat messages. Text content only.
streamOptional, defaults to false. Set true for SSE streaming — required for generations longer than 32768 tokens.
stream_optionsOptional, streaming only. Set include_usage: true to receive a final chunk carrying the usage object — same behaviour as OpenAI. Without it, streamed responses omit usage; billing is unaffected either way.
max_tokensOptional. Passed through natively. Capped at 32768 when stream is false; uncapped (up to the context window) when streaming. Reasoning tokens count toward this budget — see Limits.
temperatureOptional. Passed through natively.
top_pOptional. Passed through natively.
stopOptional. Passed through natively.
seedOptional. Passed through natively; best-effort determinism only.
nOnly n = 1 is supported.

Core models vs. deep research models

Both model families answer on POST /v1/chat/completions, and the semantics are deliberately different. The behaviour is selected by the model id in the request body, so switching model ids also switches the contract.

AspectCore models (apodex-1.1, apodex-1.1-mini)Deep research models (Deep Research / Solve / Discover tiers)
Default for streamfalse — a plain JSON response unless you opt intrue — SSE unless you explicitly opt out
Failure modeReal HTTP status codes: 400 / 401 / 402 / 429HTTP 200 even on failure; the error is carried inside the stream or body
Sampling parametersmax_tokens, temperature and top_p are passed through nativelyIgnored — the agent controls its own generation budget
ToolsNone. Nothing runs server-side; you get the model output onlyBuilt-in web search, URL fetch, code sandbox, MCP servers
Latency profileSingle forward pass — first token in the usual LLM rangeMinutes: the agent plans, searches and iterates before answering
Billing unitReal tokens: input / cached input / outputTokens plus per-use tool calls

The deep research contract is documented separately in Chat Completions.

Limits and restrictions

LimitDescription
Non-streaming max_tokens is capped at 32768

With stream: false, a max_tokens above 32768 is rejected with HTTP 400 before any generation starts. Long generations must stream — the cap does not apply to stream: true.

JSON
HTTP/1.1 400 Bad Request

{
  "error": {
    "code": "invalid_request",
    "message": "max_tokens exceeds the non-streaming limit of 32768; use stream=true for longer generations",
    "type": "invalid_request_error"
  }
}
A non-streaming request is capped at about 600s of wall clock

Independently of max_tokens, a single stream: false request has to finish generating within roughly 600 seconds. That ceiling belongs to the gateway in front of the models, so when it trips you get a gateway-level timeout — an HTTP 504 with an HTML body, not our JSON error envelope. Long generations must stream: stream: true is not subject to this limit, because bytes start flowing with the first token.

This can bite you well inside the 32768 cap. Under high concurrency with cold prefix caches, decoding slows down, so a request that normally completes in about 190s can approach the wall. Our advice: stream anything long, and if you must stay non-streaming, set your client timeout to 600s or more — several SDKs default to exactly 600s, which lands right on the boundary.

Reasoning is on by default and counts toward max_tokens

Both models think before answering. The reasoning text is returned in the reasoning_content field — on message for non-streaming responses, on delta for streamed chunks — and its tokens count toward max_tokens.

If max_tokens is set too low, the entire budget can be consumed by reasoning: the response comes back with an empty content and finish_reason: length. Leave enough headroom — 1024 or more is a sensible floor.

The Responses API subset is statelessCore models support a stateless subset of POST /v1/responses: store is forced to false. Sending store: true, previous_response_id or background: true returns HTTP 400 — carry the conversation in your own request instead.
Text onlyMultimodal input is not supported. Image, audio and file content parts are rejected — send text.
Account-level rate limitsConcurrency and tokens-per-minute are enforced per account and surface as HTTP 429. See Rate limits for the full contract.

Responses API subset

POST /v1/responses is supported as a stateless subset: single-shot request in, response out. Anything that would require us to persist state on your behalf is rejected with HTTP 400 rather than silently ignored.

ParameterSupport
storeForced to false. Sending store: true returns 400.
previous_response_idNot supported — returns 400. There is no server-side conversation to resume.
backgroundNot supported — returns 400. Requests are always executed inline.
max_output_tokensSupported. Maps to max_tokens, including the 32768 non-streaming cap.
Example
curl -X POST https://api.apodex.ai/v1/responses \
  -H "Authorization: Bearer $APODEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "apodex-1.1",
    "input": "Explain prefix caching in one paragraph.",
    "max_output_tokens": 512
  }'

Session caching with X-Session-Id

Sending the optional X-Session-Id header with a stable value for one logical conversation lets us route the turns of that conversation consistently, which significantly improves prefix cache hit rate — lower time-to-first-token and a cheaper cached-input rate on the shared prefix. If you omit the header, the server derives a key from the request content automatically.

  • Use one stable, unique value per conversation — a UUID per chat thread is ideal.
  • Reuse the same value for every turn of that conversation, including retries of the same turn.
  • Do not reuse one value across unrelated conversations, and do not put user identifiers or other sensitive data in it.
Header
X-Session-Id: <your-stable-conversation-key>

Billing

Core models are billed on real token counts reported by the model, in three tiers:

  • Input — prompt tokens that were not served from cache.
  • Cached input — prompt tokens served from the prefix cache, billed at a lower rate than fresh input.
  • Output — tokens the model generates, including any streamed partial output.

Requests with more than 200K input tokens are billed at 2× the listed rates for the entire request — the multiplier applies to input, cached input and output alike.

If the client disconnects mid-generation, the tokens already generated are still billed. Cancelling a request stops further generation but does not refund what has been produced.

Streamed responses carry the usage object only when the request sets include_usage: true in stream_options — the final chunk then reports it, exactly like OpenAI. Omitting it does not change billing: usage is metered server-side either way.

Current list prices are on the Pricing page.

Error responses

Unlike the deep research models, core models return real HTTP status codes. Errors are never wrapped in a 200 response.

StatusCodeDescription
400invalid_requestInvalid parameters — malformed body, unsupported field, multimodal content, or max_tokens above 32768 on a non-streaming request.
400model_not_foundUnknown model id, or a model your account is not entitled to. Returned as HTTP 400, not 404.
401unauthorizedMissing or invalid API key.
402insufficient_balanceInsufficient balance. Top up in the console and retry.
429rate_limitedRate limited — account concurrency or TPM exceeded. Honour Retry-After and back off.
Error format
HTTP/1.1 400 Bad Request

{
  "error": {
    "message": "model not found: gpt-4o",
    "type": "invalid_request_error",
    "code": "model_not_found"
  }
}
Docs | Apodex API Platform