AI Stupid Level
API docs

Support

API documentation

Complete developer reference for the AI Smart Router. Requests go to https://aistupidlevel.info/v1 with your aism_ key as a Bearer token.

Base URL
https://aistupidlevel.info/v1
Auth
Bearer aism_key
Format
OpenAI-compatible
Providers
6 (OpenAI, Anthropic, …)

API overview

Introduction

The AI Smart Router provides an OpenAI-compatible API that intelligently routes your requests to the best AI model based on real-time benchmarks. Use a single aism_ key — your SR (Smart Router) key — to access models from 6 providers: OpenAI, Anthropic, Google (Gemini), DeepSeek, Kimi (Moonshot), and GLM (Z.AI).

Base URL

https://aistupidlevel.info/v1

Authentication

All requests require a Bearer token in the Authorization header:

Authorization: Bearer aism_your_api_key_here

Some tools enforce an sk- prefix for API keys. The router accepts sk-aism_... — the prefix is stripped automatically.

Project keys. A key made on a workspace project’s page works the same way, but follows the project’s routing rules (strategy, allowed models, limits), pays with the project’s or workspace’s provider keys, and counts against the project’s budget and the holder’s cap in it — see the workspace guide. Keys can also expire; an expired key gets a 401 saying when it expired.

Endpoints

MethodPathDescription
POST/v1/chat/completionsChat completions (auto-routing or direct pin)
GET/v1/modelsList available models (requires auth)
POST/v1/embeddingsEmbeddings (proxied to OpenAI)
POST/v1/messagesNative Anthropic Messages API passthrough (Claude Code)
POST/v1/messages/count_tokensAnthropic token counter (free; not counted against your plan)
POST/v1/router/feedbackRate an answer up or down by its completion id
POST/v1/explainWhich model “auto” would pick for a prompt, without sending it
POST/v1/compareWhat every strategy would pick for a prompt
POST/v1/analyzeHow the router classifies a prompt

POST/v1/chat/completions

Create a chat completion. Use an auto-* virtual model for intelligent routing, or a real model ID for direct pin routing.

Request body

JSON
{
  "model": "auto-coding",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Write a Python fibonacci function"}
  ],
  "temperature": 0.7,
  "max_tokens": 1000,
  "stream": false
}

Parameters

ParameterTypeRequiredDescription
modelstringYes"auto-coding", "auto-reasoning", or a real model ID like "claude-opus-5-5"
messagesarrayYesArray of {role, content} message objects
temperaturenumberNoSampling temperature (0-2). Default varies by provider.
max_tokensnumberNoMax tokens to generate. For reasoning models use max_completion_tokens.
max_completion_tokensnumberNoMax output tokens including reasoning tokens (GPT-5.x, o-series).
streambooleanNoEnable SSE streaming. Default: false.
stream_optionsobjectNo{ include_usage: true } — emit final usage chunk in SSE.
toolsarrayNoFunction tool definitions for tool calling.
tool_choicestring|objectNo"auto", "none", "required", or {type:"function", function:{name}}.
response_formatobjectNo{ type: "json_object" } or { type: "json_schema", json_schema: {...} }.
reasoning_effortstringNo"none"|"minimal"|"low"|"medium"|"high"|"xhigh" — for reasoning models.
top_pnumberNoNucleus sampling. Default: 1.
frequency_penaltynumberNoFrequency penalty (-2 to 2). Not supported by all providers.
presence_penaltynumberNoPresence penalty (-2 to 2). Not supported by all providers.
stopstring|arrayNoStop sequences. Not supported by all providers.
seednumberNoRandom seed for reproducibility.

Code examples

from openai import OpenAI

client = OpenAI(
    api_key="aism_your_key_here",
    base_url="https://aistupidlevel.info/v1"
)

response = client.chat.completions.create(
    model="auto-coding",
    messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)

Response

JSON
{
  "id": "chatcmpl-1748250000000",
  "object": "chat.completion",
  "created": 1748250000,
  "model": "claude-opus-5-5",
  "system_fingerprint": "aism_v1_anthropic",
  "service_tier": "default",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "Hello! How can I help you today?",
      "refusal": null,
      "annotations": []
    },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 9,
    "total_tokens": 21,
    "prompt_tokens_details": { "cached_tokens": 0 },
    "completion_tokens_details": { "reasoning_tokens": 0 }
  }
}

Response headers

X-AISM-Provider
The provider that answered
X-AISM-Model
The model that answered
X-AISM-Reasoning
Why it was chosen, including any fallback
X-AISM-Latency
How long the request took
X-AISM-Request-Id
The completion id, for feedback
X-AISM-Streaming-Mode
native when streamed text arrives as the model writes it; buffered for a streamed forced tool call, which is checked before anything is sent — see Tools, JSON and streaming

Virtual models (routing strategies)

Use these as the model parameter for intelligent routing.

Model IDStrategyDescription
autoDefaultUses your saved routing strategy from Preferences
auto-taskPer requestReads each request and picks the matching benchmark: tools → tool use, design or long sessions → reasoning, code → coding, else overall; simple requests use the Best value version. The routing reason names the rule
auto-splitYour splitYour own weighted traffic split across models you choose (set it in Preferences); the rest of the split is the first fallback
auto-codingCodingBest for code generation, debugging, refactoring
auto-reasoningReasoningBest for complex analysis, math, logic
auto-consistentConsistencyAmong models within 5 points of the best one you can use, the one whose score swings least from run to run
auto-fastest-qualitySpeedAmong models within 5 points of the best one you can use, the fastest (measured latency) — auto-fastest has no quality bar
auto-creativeLegacyStill accepted and routed as auto-best — there is no creative-writing benchmark
auto-cheapestCostLowest list price per token among your providers — no quality bar
auto-valueValueMost combined-score points per measured dollar, among models within 5 points of the best one you can use
auto-value-codingValueMost coding points per dollar (measured cost of a coding run), near-top models only
auto-value-reasoningValueMost reasoning points per dollar (measured cost of a reasoning run), near-top models only
auto-value-toolingValueMost tool-use points per dollar (measured cost of a tool-use run), near-top models only
auto-value-agenticValueAlias for auto-value-tooling
auto-fastestSpeedLowest latency response time
auto-toolingTool useBest at calling tools correctly — scored on our tool-calling suite
auto-agenticTool useAlias for auto-tooling; "agentic" is what most tools call it
auto-bestOverallHighest combined score regardless of category

Direct pin routing: Send any real model ID (e.g., claude-opus-5-5, gpt-6-sol, gemini-3.8-flash; GET /v1/models lists them all) to bypass the strategy router and forward directly to that provider.

Near-top strategies (auto-value*, auto-consistent, auto-fastest-quality) only choose among models within 5 points of the best model you can use — after your keys, exclusions and limits — so a cheaper, steadier or faster pick is never a much weaker one. Value is measured: the benchmark score divided by what one identical benchmark run actually cost that model, not its list price per token.

Drift-aware routing (on by default, see Preferences): a model whose drift detector has fired for the skill your strategy relies on, or whose hourly canary is failing, is moved behind every unflagged model. It is never removed — if every candidate is flagged, the best of them is still used — and the routing reason names any model that was passed over and why.

GET/v1/models

List available models. Returns virtual auto-* models plus all real models that have been benchmarked. Requires authentication.

cURL
curl https://aistupidlevel.info/v1/models \
  -H "Authorization: Bearer aism_your_key_here"

Tools like Roo Code, Continue, Open WebUI, and LibreChat call this endpoint to populate their model dropdowns.

Tools, JSON and streaming

Tool calling works end to end. Send OpenAI-format tools; the response carries tool_calls with the provider's own ids. Send the results back as role: "tool" messages with tool_call_id, exactly as with OpenAI. The router remembers each model's own turn for 24 hours (Claude's thinking blocks, OpenAI reasoning items, Gemini thought signatures), so multi-step agent loops keep working, and a tool loop stays on the model that started it.

tool_choice: auto and none work everywhere, and required or a named function works on every model. OpenAI, Gemini, DeepSeek V4 (thinking is switched off for that one request), Kimi K3, and Claude other than Fable 5.1 and Sonnet 5.5 enforce it natively, and routed requests that force a tool go to those first. The rest (Kimi K2.7 Code, GLM-5.3, Claude Fable 5.1 and Sonnet 5.5) cannot be forced by their APIs — GLM-5.3 even accepts the setting and ignores it — so the router asks in words (an instruction for that turn), checks that the answer really is the tool call, retries once, and otherwise falls back or answers 502 tool_choice_not_honoured. It never hands you prose when you forced a tool. Streamed forced calls arrive in one piece (X-AISM-Streaming-Mode: buffered), because the answer is checked before anything is sent.

JSON output: response_format json_object and json_schema are supported for every provider. The schema is enforced natively by OpenAI, Gemini and the Claude models that support structured output (when every object sets additionalProperties: false); DeepSeek, Kimi and GLM receive the schema as an instruction in JSON mode.

Streaming (stream: true) is real: text arrives as the model writes it (X-AISM-Streaming-Mode: native). Tool calls arrive in one chunk each once the model has finished them, then the finish reason, then usage if you set stream_options.include_usage. If the chosen model fails before sending anything, the next fallback is tried; after the first byte a failure ends the stream with an error event.

Text only, by design. The router picks a model from our benchmark results for coding, reasoning and tool use; none of those measure image, audio or file understanding, so a request with them gets a 400 unsupported_content rather than a routing decision we cannot back. n must be 1. Requests can be up to 32 MB — about a million tokens of code in context.

Rate a response

Ratings help routing learn from real use:

cURL
curl -X POST https://aistupidlevel.info/v1/router/feedback \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer aism_your_key_here" \
  -d '{"id": "chatcmpl-...", "rating": "up"}'

Use the id from the completion (also in X-AISM-Request-Id); rating is "up"/1 or "down"/-1. Ratings nudge rankings only slightly, and only once enough have accumulated.

POST/v1/embeddings

Generate embeddings via OpenAI's embedding models. Required by Continue, LibreChat, Open WebUI, and AnythingLLM for RAG features.

cURL
curl -X POST https://aistupidlevel.info/v1/embeddings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer aism_your_key_here" \
  -d '{"model": "text-embedding-3-small", "input": "Hello world"}'

Requires an active OpenAI provider key. Supported models: text-embedding-3-small (also auto-embedding), text-embedding-3-large. Each call counts as one request against your plan, and per-key budgets apply.

POST/v1/messagesAnthropic

Native Anthropic Messages API passthrough. Unlocks Claude Code, Cline's Anthropic provider, Roo Code's Anthropic provider, and TypingMind's Anthropic preset.

Accepts aism_ keys via either x-api-key or Authorization: Bearer header. Forwards the anthropic-version header (defaults to 2023-06-01) and any anthropic-beta header as sent. POST /v1/messages/count_tokens is passed through too; it is free at Anthropic, so it is not counted against your plan.

Claude Code

Shell
export ANTHROPIC_BASE_URL="https://aistupidlevel.info"
export ANTHROPIC_API_KEY="aism_your_key_here"
claude

There is no routing on this path: the request goes to Anthropic, with your Anthropic key, for the Claude model it names. Your plan allowance, budgets and request logs apply as on the other endpoints.

cURL
curl -X POST https://aistupidlevel.info/v1/messages \
  -H "Content-Type: application/json" \
  -H "x-api-key: aism_your_key_here" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-5-5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

Requires an active Anthropic provider key. Returns native Anthropic response format (not OpenAI-translated).

Error handling

HTTP codeerror.typeerror.codeDescription
400invalid_request_errorinvalid_messagesinvalid_toolsunsupported_contentmodel_not_foundThe request cannot be routed as sent (the message says what to change)
400invalid_request_errorprovider_rejected_requestThe provider rejected the request itself; its own words are in the message
400invalid_request_errorprovider_key_rejectedno_provider_keysYour provider key is missing or was refused — add or update it in Providers
400invalid_request_errorno_routable_modelYour preferences exclude every model (the message names the setting)
401authentication_errorinvalid_api_keyMissing or invalid aism_ key
401authentication_errorexpired_api_keyThe key had an expiry date and it has passed (the message says when)
400invalid_request_errorpinning_not_allowedmodel_not_allowedprovider_not_allowedProject keys: the project routes every request, or does not allow that model or provider
403permission_errornot_in_workspacenot_in_projectseat_requiredproject_deletedplan_lapsedProject keys: the holder left, lost their seat, or the project or its plan is gone
429rate_limit_errorrate_limitedProject keys: the project’s requests-per-minute limit for this key (see Retry-After)
429rate_limit_errorproject_budget_exceededProject keys: the request could take the project past its monthly budget
429rate_limit_errormember_cap_reachedProject keys: you reached your monthly cap in the project
429rate_limit_errorbudget_downgradedProject keys: the budget is spent and the project now routes only (cheapest models); naming a model is refused
429rate_limit_errorallowance_exhaustedThis month's requests are used up and you have no prepaid credits
429rate_limit_errorinsufficient_quotaThis key's monthly hard budget would be exceeded
429rate_limit_errorprovider_quota_exceededYour provider account refused for credit or rate limits
413——The request body is over 32 MB
502api_errormodel_unavailableEvery model tried failed on the provider side
502api_errortool_choice_not_honouredYou forced a tool call and the model answered without one, twice (only models that cannot be forced natively; see Tools above)
500server_errorinternal_errorInternal server error
JSON
{
  "error": {
    "message": "Invalid API key. Generate a new key at https://aistupidlevel.info/router/keys",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}

SDKs use error.type and error.code for retry decisions. These match the OpenAI standard.

Integration examples

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="auto-coding",
    openai_api_key="aism_your_key_here",
    openai_api_base="https://aistupidlevel.info/v1"
)
response = llm.invoke("Write a Python function")
print(response.content)

Questions? Check the Help center