Models and routing
The models ModelBeat can serve, what "auto" does, and how to pin a specific model.
The model field does more work here than on a single-provider API. It accepts either
auto, which lets ModelBeat choose, or the id of a specific model, which pins the
request to it.
model: "auto" is the point
r = client.chat.completions.create(
model="auto",
messages=[{"role": "user", "content": "summarise this changelog"}],
)ModelBeat picks the cheapest model that can actually serve the request, then tells you
which one it used in routing_info. Selection gates on four things at once:
- output cap. A model whose
max_output_tokensis below yourmax_tokensis excluded. - context window. A model whose input limit is below your prompt is excluded.
- capabilities. An image in the request excludes text-only models.
- quality floor. A
codeorreasoningtask hint requires quality tier 3 or above.
Among what survives, cost decides. That is why a small request lands on the cheapest rung and a 32,000-token output request does not.
If nothing survives the gates you get a 400 with a reason such as no_eligible_candidate.
See Errors.
Pinning a specific model
Name it instead of auto:
r = client.chat.completions.create(
model="claude-sonnet-4-5",
messages=[{"role": "user", "content": "..."}],
)A pin is not an absolute guarantee, and the two ways it can be refused behave differently:
- Your policy forbids the model. You get a
400withpin_not_permitted. Nothing is served and nothing is charged. - The model cannot clear the hard gates, meaning it is retired, unrecognised, or
ineligible for the request (output cap, context window, capabilities). The router falls
through to
autoand serves a different model. This is not silent: the response carriesx-modelbeat-routing-notice: requested_ineligible, androuting_info.modelnames what actually answered. See Routing transparency.
A pin is not a guarantee
If you need a pinned model to be honoured or to fail, never substituted, check
x-modelbeat-routing-notice and treat its presence as an error in your own code.
The catalogue
Every model runs on Amazon Bedrock in us-west-2. Prices are USD per 1,000 tokens.
| Model | In | Out | Max output | Context | Tier | Latency | Capabilities |
|---|---|---|---|---|---|---|---|
nova-micro | 0.000035 | 0.00014 | 5,000 | 128,000 | 1 | fast | json, function calling |
nova-2-lite | 0.00033 | 0.00275 | 64,000 | 1,000,000 | 2 | fast | json, function calling, vision |
claude-haiku-4-5 | 0.001 | 0.005 | 64,000 | 200,000 | 3 | fast | json, function calling, vision |
claude-sonnet-4-5 | 0.0033 | 0.0165 | 64,000 | 200,000 | 4 | standard | json, function calling, vision |
claude-opus-4-5 | 0.0055 | 0.0275 | 64,000 | 200,000 | 5 | slow | json, function calling, vision |
Two things worth reading off that table:
nova-microis text-only. It has novisioncapability, deliberately, so it can never win an image request, even though it is by far the cheapest.nova-microcaps output at 5,000 tokens. Ask for more and it is gated out, which is the single most common reason a cheap request moves up a rung.
The catalogue is served from the registry and refreshes without a gateway restart, so this
table can change. routing_info on your own response is always authoritative.
Fallbacks
If the chosen model fails, ModelBeat retries down a short fallback chain rather than failing the request. When that happens the response says so:
"routing_info": {
"provider": "bedrock",
"model": "claude-haiku-4-5",
"is_fallback": true,
"primary_provider": "bedrock",
"primary_model": "claude-sonnet-4-5"
}The hold placed against your balance covers the chosen model and its fallbacks, so a fallback never costs more than was reserved. See Costs.
What is not supported
/v1/embeddings and /v1/async/* are present on the gateway but outside the supported
surface. See Limits.
Listing models programmatically
models = client.models.list()
for m in models.data:
print(m.id)GET /v1/models is authenticated (requires a valid API key) and returns the current
catalog. It is rate-limited but never metered, so no balance is consumed. The response
matches the OpenAI shape, so any stock OpenAI SDK works unchanged.