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.
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.
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.
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | Malformed body or unknown field |
| 400 | unsupported_content | A content type the model cannot take, for example an image |
| 400 | empty_input | No user message in the request |
| 401 | unauthorized | Key missing, invalid or revoked |
| 402 | insufficient_credits | Free pool spent and no prepaid credit |
| 402 | spend_limit | Daily spend cap of the key reached |
| 402 | guardrail_budget_exceeded | Spend budget of the guardrail on this key is exhausted |
| 403 | ip_not_allowed | Request from an IP outside the key allowlist |
| 403 | model_not_allowed | Model outside the allowlist of the key or its guardrail |
| 403 | content_blocked | A guardrail rejected the request |
| 404 | model_not_found | Unknown model id or variant |
| 413 | input_too_long | Prompt exceeds the model context |
| 429 | rate_limited | Over the per-minute limit; retry after a pause |
| 429 | quota_exceeded | Daily token or request cap of the key reached |
| 503 | no_provider | No live provider for the model right now; retry or use aetron/auto |
| 503 | guardrail_unavailable | The 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 →