Docs

Send your first request

AETRON Router speaks the OpenAI and Anthropic APIs. If you have a client for either, you are one base URL away.

Quickstart

Create a key on the API Keys page. The secret is shown once — store it then.

Base URL https://api-router.aetron.io/v1 Auth Authorization: Bearer sk-aetr-live-…

Same body you already send to OpenAI. Swap the model with a string.

curl https://api-router.aetron.io/v1/chat/completions \
  -H "Authorization: Bearer $AETRON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "aetron/qwen3.5-9b-gguf-q4-k-m",
    "messages": [{ "role": "user", "content": "hi" }]
  }'

Browse the full catalog with live pricing. The model id is what you pass. Models with no price are free. Models.

OpenAI-compatible

POST /v1/chat/completions takes the same body as OpenAI: messages, temperature, max_tokens, stream, tools. GET /v1/models lists what your key can call.

curl https://api-router.aetron.io/v1/models -H "Authorization: Bearer $AETRON_KEY"

Anthropic-compatible

POST /v1/messages speaks the Messages API: system, messages, max_tokens, stream, tools. Point the Anthropic SDK at the base URL without /v1 — the SDK adds it.

curl https://api-router.aetron.io/v1/messages \
  -H "Authorization: Bearer $AETRON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "aetron/qwen3.5-9b-gguf-q4-k-m",
    "max_tokens": 512,
    "system": "You are terse.",
    "messages": [{ "role": "user", "content": "hi" }]
  }'

Streaming

Pass stream: true and read server-sent events. With stream_options.include_usage the final frame carries usage; tool calls arrive as a final tool_calls frame.

stream = client.chat.completions.create(
    model="aetron/qwen3.5-9b-gguf-q4-k-m",
    messages=[{"role": "user", "content": "write a haiku"}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:
        print("\n", chunk.usage.total_tokens, "tokens")

Tool calling

Send tools in the OpenAI or Anthropic shape. The model answers with tool_calls; return results as tool messages and continue the conversation.

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

r = client.chat.completions.create(
    model="aetron/qwen3.5-9b-gguf-q4-k-m",
    messages=[{"role": "user", "content": "Weather in Lisbon?"}],
    tools=tools,
)
call = r.choices[0].message.tool_calls[0]
# run get_weather(**json.loads(call.function.arguments)), then continue:
# messages += [r.choices[0].message, {"role": "tool", "tool_call_id": call.id, "content": "..."}]

Model ids and variants

Ids look like aetron/<model>. Append :thinking to let the model reason before answering, :nitro to prefer the fastest live provider. aetron/auto lets the router pick a connected model.

aetron/qwen3.5-9b-gguf-q4-k-m # the model as listed aetron/qwen3.5-9b-gguf-q4-k-m:thinking # reason before answering aetron/qwen3.5-9b-gguf-q4-k-m:nitro # fastest live provider aetron/auto # let the router choose

Errors and limits

Errors come as {"error": {"code", "message"}} with a matching HTTP status. A key may make 120 requests a minute by default; daily token, request and spend caps are yours to set per key.

StatusCodeWhen
400invalid_requestMalformed body or unknown field
400unsupported_contentA content type the model cannot take, for example an image
400empty_inputNo user message in the request
401unauthorizedKey missing, invalid or revoked
402insufficient_creditsFree pool spent and no prepaid credit
402spend_limitDaily spend cap of the key reached
402guardrail_budget_exceededSpend budget of the guardrail on this key is exhausted
403ip_not_allowedRequest from an IP outside the key allowlist
403model_not_allowedModel outside the allowlist of the key or its guardrail
403content_blockedA guardrail rejected the request
404model_not_foundUnknown model id or variant
413input_too_longPrompt exceeds the model context
429rate_limitedOver the per-minute limit; retry after a pause
429quota_exceededDaily token or request cap of the key reached
503no_providerNo live provider for the model right now; retry or use aetron/auto
503guardrail_unavailableThe guardrail could not be evaluated; retry

Free tier

Every account gets 3M tokens a day, reset at 00:00 UTC. Free-model traffic never touches the pool. Once the daily pool is spent, paid models draw on your prepaid credit — and only then.

Pricing →