curl --request GET \
--url https://api.opper.ai/v3/compat/models \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.opper.ai/v3/compat/models"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.opper.ai/v3/compat/models', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"created": 123,
"id": "<string>",
"object": "<string>",
"owned_by": "<string>",
"context_length": 123,
"opper": {
"kind": "<string>",
"capabilities": [
"<string>"
],
"country": "<string>",
"description": "<string>",
"gdpr_residency": "<string>",
"maker": "<string>",
"maker_country": "<string>",
"max_output_tokens": 123,
"members": [
"<string>"
],
"region": "<string>",
"type": "<string>",
"verification": "<string>",
"version": 123,
"zdr": {
"caching": true,
"logging": true,
"moderation": true,
"subprocessors": true,
"training": true
}
},
"pricing": {
"completion": "<string>",
"prompt": "<string>",
"input_cache_read": "<string>",
"input_cache_write": "<string>",
"input_cache_write_1h": "<string>",
"internal_reasoning": "<string>",
"web_search": "<string>"
}
}
],
"object": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"meta": {}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"meta": {}
}List Models
OpenAI Models API compatible endpoint. Returns everything the caller can put in model — in OpenAI’s models.list shape — so tools that point an OpenAI-compatible base URL at /v3/compat (gateways, n8n, LangChain, etc.) can discover the live catalogue without hardcoding model IDs.
Every entry carries opper.kind, which names what it is:
model— a concrete catalog row (LLM or embedding), e.g.anthropic/claude-sonnet-4.5. Pinning this id pins that provider.pool— a bare model name that load-balances across providers, e.g.claude-sonnet-4.5.opper.memberslists the catalog rows it routes over. Listed only for names that genuinely fan out (two or more routable members).dynamic_route— one of the calling org’s deployed routing graphs, addressed asdynamic/<name>.opper.versionis the deployed version a call would execute. Org-scoped to the API key; draft-only routes are not listed. No pricing is reported — the graph picks the model per request — butcontext_lengthandopper.max_output_tokensARE, as the smallest any reachable candidate offers: a floor is a guarantee rather than a guess, and clients that must size a context before calling would otherwise have to invent one. Omitted when any candidate cannot be resolved here (e.g. an org-scoped BYOK model).
Narrow with ?type= (comma-separated, e.g. ?type=pool,dynamic_route); omitting it returns all three kinds, with concrete models first (their long-standing order is unchanged), then pools, then routes.
Entries additionally carry OpenRouter-shaped pricing (USD per token) and context_length, plus an opper block holding the entry’s type (llm or embedding — this list carries both, and capabilities cannot tell them apart), the model’s capabilities (text, tools, vision, pdf, structured_output, … — the same vocabulary as /v3/models), its max_output_tokens, and a compliance summary (region, country, zdr, gdpr_residency, verification) so a client can declare what a model can do and filter on residency/ZDR criteria in one call; zdr is the tri-state retention facts object (logging, moderation, caching, training, subprocessors; null = not established), not a summary word — derive what you need from it; full data-handling detail lives on /v3/models?include=route. A pool reports a capability or compliance property only when EVERY member has it, takes the smallest context_length / max_output_tokens across members, and prices at the worst case, so a capability check, a residency filter or a pre-call cost estimate can never be flattered by one lucky member. dynamic_route entries carry no capabilities for the same reason they carry no pricing. The whole listing is scoped to the caller’s comply allowlist: denied models, denied pool members, pools with no permitted member, and routes whose every model node is denied are all absent. Featured models first, then ID-ascending; no pagination, matching OpenAI.
curl --request GET \
--url https://api.opper.ai/v3/compat/models \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.opper.ai/v3/compat/models"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.opper.ai/v3/compat/models', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": [
{
"created": 123,
"id": "<string>",
"object": "<string>",
"owned_by": "<string>",
"context_length": 123,
"opper": {
"kind": "<string>",
"capabilities": [
"<string>"
],
"country": "<string>",
"description": "<string>",
"gdpr_residency": "<string>",
"maker": "<string>",
"maker_country": "<string>",
"max_output_tokens": 123,
"members": [
"<string>"
],
"region": "<string>",
"type": "<string>",
"verification": "<string>",
"version": 123,
"zdr": {
"caching": true,
"logging": true,
"moderation": true,
"subprocessors": true,
"training": true
}
},
"pricing": {
"completion": "<string>",
"prompt": "<string>",
"input_cache_read": "<string>",
"input_cache_write": "<string>",
"input_cache_write_1h": "<string>",
"internal_reasoning": "<string>",
"web_search": "<string>"
}
}
],
"object": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"meta": {}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": "<unknown>"
},
"meta": {}
}Authorizations
API key authentication. Pass your API key as a Bearer token.
Query Parameters
Comma-separated entry kinds to return: model, pool, dynamic_route. Omit for all three.
"pool,dynamic_route"