API reference / LLMs
LLMs
The catalogue is real and complete, but it does not have a route of its own: it
rides back as the models key on
GET /api/settings. Choosing
a model is a settings write, not a call to a model resource.
Two model slots are driven independently: a quality model for a one shot turn and a fast model for the always on live conversation. The catalogue is built from what Bedrock actually serves in the box's own region, so it is not Claude only. Which models you may pick is decided by data residency, and that decision is stated on each row rather than left for a client to infer.
Read the catalogue
curl "https://avatar.zelibot.xyz/api/settings" -H "X-Api-Key: zsk_live_..."const { models, effort_levels } = await admin.management.getSettings();{
"models": [
{
"id": "au.anthropic.claude-opus-5-5",
"label": "Claude Opus 5.5",
"tiers": ["quality", "fast"],
"supports_sampling": false,
"supports_effort": true,
"effort_max": true,
"reasoning": "always",
"forced_tool_choice_supported": false,
"default_reasoning": "low",
"provider": "anthropic",
"residency": "au",
"selectable": true
},
{
"id": "openai.gpt-oss-120b-1:0",
"label": "GPT OSS 120b",
"tiers": [],
"supports_sampling": false,
"supports_effort": false,
"effort_max": false,
"reasoning": "none",
"default_reasoning": "off",
"provider": "openai",
"residency": "au",
"selectable": true
}
],
"effort_levels": ["low", "medium", "high", "xhigh", "max"],
"reasoning_levels": ["off", "low", "medium", "high"]
}| Field | Type | Meaning |
|---|---|---|
id | string | The value to write to model or live_model |
label | string | A name for a person, with the trade off in brackets |
tiers | string[] | quality, fast, both, or empty when there is no advice |
supports_sampling | boolean | Whether top_p and temperature are accepted |
supports_effort | boolean | Whether effort is accepted |
effort_max | boolean | Whether the max effort level is accepted |
reasoning | string | How the model takes a thinking level: adaptive, always (thinking cannot be switched off, so off runs the least thinking the model allows), budget, or none (the level is ignored) |
forced_tool_choice_supported | boolean | Present and false on a model that refuses a forced tool call. The server asks such a model to use its reply tool instead of forcing it. Absent means supported |
default_reasoning | string | The level a persona gets on this model when it has not chosen one |
provider | string | anthropic, openai, mistral, and so on |
residency | string | au, apac or global |
selectable | boolean | Whether this deployment will let you choose it |
Both mean the same thing: this is a model nobody on our side has measured. The capability flags are probe results, not something the provider advertises, so an unmeasured model is reported as accepting neither sampling nor effort. That understates most of them on purpose. Being wrong the other way costs a 400 in the middle of a conversation; being wrong this way costs two fields a client chose not to send.
Nothing enforces it. The server applies whatever model id it is sent for either
slot, and pointing the live slot at the quality model to trade latency for
depth is a supported thing to do. Use tiers to group a picker
under a heading that states the trade off, and do not reintroduce it as a hard
filter: doing that once hid the newest model from the live picker entirely and
read as a missing model rather than as advice.
Residency, and what selectable is for
residency is derived and is never hand written, because a hand maintained
residency claim is exactly the kind of fact that rots. Ordered most resident
first: au, then apac, then global. When one model is offered at more than
one address, the most resident one wins, so a model available in country is
never advertised at an offshore address. The one exception is a model whose only
offshore copy is genuinely newer: both rows are returned, so the in country
option is never deleted by a release you cannot use.
Two id shapes arrive, and they answer the residency question differently.
au.anthropic.claude-opus-5-5 carries a routing geography, so the id says where it
runs. openai.gpt-oss-120b-1:0 carries none, because it does not route: Bedrock
serves it from the region the call was made in. That absence is the strongest
residency claim on the menu, not a missing field, and it is why those models are
reported au on a Sydney box.
selectable is a separate field rather than something a client derives from
residency, because "au means allowed" is a rule that gets duplicated at every
call site until one copy disagrees. Only au models are selectable without an
explicit opt in. Residency is this product's central claim, so the default is the
conservative one.
Writing a non selectable model to model or live_model is refused with a 400
and setting_refused, and the message names which of the two refusals it is: a
model that does not exist, or one this deployment will not send data to. Both
slots are validated by the same rule, because a caller refused on one could
otherwise simply use the other.
Choose a model
Writing is a settings write:
curl -X POST "https://avatar.zelibot.xyz/api/settings" \
-H "X-Api-Key: zsk_live_..." \
-H "Content-Type: application/json" \
-d '{"model": "au.anthropic.claude-opus-5-5", "live_model": "au.anthropic.claude-haiku-4-5"}'The capability flags are what a client should gate its own form on: sending
temperature to a model whose supports_sampling is false is a request the
upstream provider will reject.
Full field documentation is on the Personas page, which is where the settings record lives.
Not served in this group
- Bring your own LLM. There is no route to register an endpoint URL, a secret or a request format, and no store for one. It also cuts against the residency rule above, so it is a product decision rather than a missing handler.
GET /llms,POST /llms, and read, update or delete by id. There is no LLM record to address. The catalogue is derived from Bedrock's own listings at boot and served as a field.- Search, pagination and a default inclusion flag on the catalogue. It returns the complete list.