Optimized Router API

Send category-routed completions. Omit thread_id to start a stored chat; send it back to continue. The server receives the full message history on every turn. All routes below require an inbound client key (rk_live_...).

Request flow

Threads are owned by the inbound API key. Send only the latest prompt. Do not create a thread first and do not resend prior messages. POST /v1/optimized-router creates a thread when thread_id is omitted or null, and continues that thread when thread_id is present.

  1. New chat: POST /v1/optimized-router with category and prompt (no thread_id). The server creates a thread, sends that prompt, stores both turns, and returns thread_id.
  2. Continue: send the same endpoint with that thread_id plus the next prompt.
  3. The server loads the thread (404 if missing or owned by another key), rebuilds history in seq order, appends the new user message, and sends the full array upstream.
  4. On success it stores the user message and assistant reply, updates last_message_at, and returns { "response", "thread_id" }.
  5. GET /threads lists chats for the sidebar. GET /threads/{thread_id}/messages loads a previous chat for the UI.

Keep the returned thread_id on the client and send it on the next turn. Omitting it starts a new chat. POST /threads is optional and not required to send a message.

Authentication

HeaderExample
AuthorizationBearer rk_live_...
X-API-Keyrk_live_...

Bearer takes precedence when both are sent. Missing or invalid keys return 401 with WWW-Authenticate: Bearer.

POST /v1/optimized-router

POST/v1/optimized-routerAPI key

Client picks the category (no app-side classifier). Category selects the model. This is the only call needed to start or continue a stored chat.

Request

FieldTypeRequiredDescription
categorystringyesSee categories
promptstringyesLatest user turn. Prior messages are loaded from the thread
thread_idstringnoContinue this thread. Omit or null to create a new one

New thread

curl -s https://gateway.pixis.ai/v1/optimized-router \
  -H 'Authorization: Bearer rk_live_YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "category": "sql",
    "prompt": "Write a PostgreSQL query to calculate ROAS."
  }'

Continue a thread

curl -s https://gateway.pixis.ai/v1/optimized-router \
  -H 'Authorization: Bearer rk_live_YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "category": "sql",
    "prompt": "Now filter to last 7 days.",
    "thread_id": "THREAD_ID"
  }'

Response

{
  "response": "SELECT ...",
  "thread_id": "THREAD_ID"
}

thread_id is always returned. Use it on the next request to keep context. This endpoint does not set X-Router-* headers.

POST /threads

POST/threadsAPI key

Optional. Create an empty thread without sending a message. Starting a chat does not require this — omit thread_id on POST /v1/optimized-router instead. Title is optional; if omitted, the first persisted user prompt becomes the title (max 255 characters).

{
  "title": "ROAS query"
}
{
  "id": "THREAD_ID",
  "title": "ROAS query",
  "status": "active",
  "last_message_at": null,
  "created_at": "2026-08-18T10:00:00+00:00",
  "updated_at": "2026-08-18T10:00:00+00:00"
}

GET /threads

GET/threadsAPI key

List active threads for the calling key, newest activity first (last_message_at, then created_at).

QueryTypeDescription
limitintPage size, default 50, max 100
cursorstringOpaque cursor from the previous page
{
  "success": true,
  "threads": [
    {
      "id": "THREAD_ID",
      "title": "ROAS query",
      "status": "active",
      "last_message_at": "2026-08-18T10:01:00+00:00",
      "created_at": "2026-08-18T10:00:00+00:00",
      "updated_at": "2026-08-18T10:01:00+00:00"
    }
  ],
  "next_cursor": null
}

GET /threads/{thread_id}

GET/threads/{thread_id}API key

Fetch one thread. Returns 404 not_found if the id is unknown, deleted, or owned by another key.

GET /threads/{thread_id}/messages

GET/threads/{thread_id}/messagesAPI key

Return stored messages in seq order for the UI. Same ownership rules as GET thread.

QueryTypeDescription
after_seqintReturn rows with seq greater than this value (default 0)
limitintPage size, default 200, max 500
{
  "success": true,
  "thread_id": "THREAD_ID",
  "messages": [
    { "id": 1, "seq": 1, "role": "user", "content": "Write a PostgreSQL query to calculate ROAS.", "created_at": "2026-08-18T10:00:30+00:00" },
    { "id": 2, "seq": 2, "role": "assistant", "content": "SELECT ...", "model_requested": "sql", "latency_ms": 420, "created_at": "2026-08-18T10:00:31+00:00" }
  ],
  "next_seq": null
}

next_seq is set when another page exists; pass it as after_seq on the next request.

Errors

{
  "success": false,
  "error": {
    "type": "invalid_category",
    "message": "Unknown category 'foo'. Valid: simple, coding, ..."
  }
}
typeStatus
missing_client_key / invalid_client_key401
client_rate_limit429
invalid_api_key401
bad_request400
not_found404
invalid_model / invalid_category / invalid_policy400 / 404
router_model_unconfigured400
model_not_allowed403
rate_limit429
timeout504
upstream_unavailable / provider_unavailable503 / 502
provider_error / unexpected_api_response502
internal_error500

On retryable upstream failures (timeout, rate_limit, provider_unavailable, upstream_unavailable), the app retries once with FALLBACK_MODEL_DEFAULT (if configured and different from the primary). A failed upstream call is not written to the thread.

Categories

Category values select which model the endpoint uses. Hyphens and spaces normalize to underscores.

CategoryEnvDefault model
simpleMODEL_SIMPLEgoogle/gemini-2.5-flash
codingMODEL_CODINGanthropic/claude-sonnet-4-5
sqlMODEL_SQLopenai/gpt-5.1
analysisMODEL_ANALYSISgoogle/gemini-2.5-pro
reasoningMODEL_REASONINGdeepseek/deepseek-reasoner
extractionMODEL_EXTRACTIONopenai/gpt-4.1-mini
backend_machineryMODEL_BACKEND_MACHINERYopenai/gpt-5.1
routineMODEL_ROUTINEgoogle/gemini-2.5-flash
analyticalMODEL_ANALYTICALgoogle/gemini-2.5-pro
judgmentMODEL_JUDGMENTanthropic/claude-sonnet-4-5
defaultMODEL_DEFAULTfalls back to DEFAULT_MODEL

If a category model is unset, the router uses the matching Von-layer model, then MODEL_DEFAULT.