

Support
Complete developer reference for the AI Smart Router. Requests go to https://aistupidlevel.info/v1 with your aism_ key as a Bearer token.
https://aistupidlevel.info/ v1Bearer aism_keyThe 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).
https://aistupidlevel.info/ v1All requests require a Bearer token in the Authorization header:
Authorization: Bearer aism_your_api_key_hereSome 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.
| Method | Path | Description |
|---|---|---|
| POST | /v1/chat/completions | Chat completions (auto-routing or direct pin) |
| GET | /v1/models | List available models (requires auth) |
| POST | /v1/embeddings | Embeddings (proxied to OpenAI) |
| POST | /v1/messages | Native Anthropic Messages API passthrough (Claude Code) |
| POST | /v1/messages/count_tokens | Anthropic token counter (free; not counted against your plan) |
| POST | /v1/router/feedback | Rate an answer up or down by its completion id |
| POST | /v1/explain | Which model “auto” would pick for a prompt, without sending it |
| POST | /v1/compare | What every strategy would pick for a prompt |
| POST | /v1/analyze | How the router classifies a prompt |
/v1/chat/completionsCreate a chat completion. Use an auto-* virtual model for intelligent routing, or a real model ID for direct pin routing.
{
"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
}| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | "auto-coding", "auto-reasoning", or a real model ID like "claude-opus-5-5" |
messages | array | Yes | Array of {role, content} message objects |
temperature | number | No | Sampling temperature (0-2). Default varies by provider. |
max_tokens | number | No | Max tokens to generate. For reasoning models use max_completion_tokens. |
max_completion_tokens | number | No | Max output tokens including reasoning tokens (GPT-5.x, o-series). |
stream | boolean | No | Enable SSE streaming. Default: false. |
stream_options | object | No | { include_usage: true } — emit final usage chunk in SSE. |
tools | array | No | Function tool definitions for tool calling. |
tool_choice | string|object | No | "auto", "none", "required", or {type:"function", function:{name}}. |
response_format | object | No | { type: "json_object" } or { type: "json_schema", json_schema: {...} }. |
reasoning_effort | string | No | "none"|"minimal"|"low"|"medium"|"high"|"xhigh" — for reasoning models. |
top_p | number | No | Nucleus sampling. Default: 1. |
frequency_penalty | number | No | Frequency penalty (-2 to 2). Not supported by all providers. |
presence_penalty | number | No | Presence penalty (-2 to 2). Not supported by all providers. |
stop | string|array | No | Stop sequences. Not supported by all providers. |
seed | number | No | Random seed for reproducibility. |
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)
{
"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 }
}
}X-AISM-ProviderX-AISM-ModelX-AISM-ReasoningX-AISM-LatencyX-AISM-Request-IdX-AISM-Streaming-Modenative 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 streamingUse these as the model parameter for intelligent routing.
| Model ID | Strategy | Description |
|---|---|---|
auto | Default | Uses your saved routing strategy from Preferences |
auto-task | Per request | Reads 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-split | Your split | Your own weighted traffic split across models you choose (set it in Preferences); the rest of the split is the first fallback |
auto-coding | Coding | Best for code generation, debugging, refactoring |
auto-reasoning | Reasoning | Best for complex analysis, math, logic |
auto-consistent | Consistency | Among models within 5 points of the best one you can use, the one whose score swings least from run to run |
auto-fastest-quality | Speed | Among models within 5 points of the best one you can use, the fastest (measured latency) — auto-fastest has no quality bar |
auto-creative | Legacy | Still accepted and routed as auto-best — there is no creative-writing benchmark |
auto-cheapest | Cost | Lowest list price per token among your providers — no quality bar |
auto-value | Value | Most combined-score points per measured dollar, among models within 5 points of the best one you can use |
auto-value-coding | Value | Most coding points per dollar (measured cost of a coding run), near-top models only |
auto-value-reasoning | Value | Most reasoning points per dollar (measured cost of a reasoning run), near-top models only |
auto-value-tooling | Value | Most tool-use points per dollar (measured cost of a tool-use run), near-top models only |
auto-value-agentic | Value | Alias for auto-value-tooling |
auto-fastest | Speed | Lowest latency response time |
auto-tooling | Tool use | Best at calling tools correctly — scored on our tool-calling suite |
auto-agentic | Tool use | Alias for auto-tooling; "agentic" is what most tools call it |
auto-best | Overall | Highest 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.
/v1/modelsList available models. Returns virtual auto-* models plus all real models that have been benchmarked. Requires authentication.
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.
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.
Ratings help routing learn from real use:
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.
/v1/embeddingsGenerate embeddings via OpenAI's embedding models. Required by Continue, LibreChat, Open WebUI, and AnythingLLM for RAG features.
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.
/v1/messagesAnthropicNative 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.
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 -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).
| HTTP code | error.type | error.code | Description |
|---|---|---|---|
| 400 | invalid_request_error | invalid_messages/ invalid_tools/ unsupported_content/ model_not_found | The request cannot be routed as sent (the message says what to change) |
| 400 | invalid_request_error | provider_rejected_request | The provider rejected the request itself; its own words are in the message |
| 400 | invalid_request_error | provider_key_rejected/ no_provider_keys | Your provider key is missing or was refused — add or update it in Providers |
| 400 | invalid_request_error | no_routable_model | Your preferences exclude every model (the message names the setting) |
| 401 | authentication_error | invalid_api_key | Missing or invalid aism_ key |
| 401 | authentication_error | expired_api_key | The key had an expiry date and it has passed (the message says when) |
| 400 | invalid_request_error | pinning_not_allowed/ model_not_allowed/ provider_not_allowed | Project keys: the project routes every request, or does not allow that model or provider |
| 403 | permission_error | not_in_workspace/ not_in_project/ seat_required/ project_deleted/ plan_lapsed | Project keys: the holder left, lost their seat, or the project or its plan is gone |
| 429 | rate_limit_error | rate_limited | Project keys: the project’s requests-per-minute limit for this key (see Retry-After) |
| 429 | rate_limit_error | project_budget_exceeded | Project keys: the request could take the project past its monthly budget |
| 429 | rate_limit_error | member_cap_reached | Project keys: you reached your monthly cap in the project |
| 429 | rate_limit_error | budget_downgraded | Project keys: the budget is spent and the project now routes only (cheapest models); naming a model is refused |
| 429 | rate_limit_error | allowance_exhausted | This month's requests are used up and you have no prepaid credits |
| 429 | rate_limit_error | insufficient_quota | This key's monthly hard budget would be exceeded |
| 429 | rate_limit_error | provider_quota_exceeded | Your provider account refused for credit or rate limits |
| 413 | — | — | The request body is over 32 MB |
| 502 | api_error | model_unavailable | Every model tried failed on the provider side |
| 502 | api_error | tool_choice_not_honoured | You forced a tool call and the model answered without one, twice (only models that cannot be forced natively; see Tools above) |
| 500 | server_error | internal_error | Internal server error |
{
"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.
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