GET /v1/models
GET /v1/models returns cc-router’s fixed list of virtual models. The list does not reflect upstream subscriptions — it is a hard-coded alias table so that Claude Code, Claude Desktop, Codex CLI, Open WebUI, and any other client speaking the Anthropic or OpenAI protocol all see the same virtual model catalog. The three chat endpoints (/v1/messages, /v1/responses, /v1/chat/completions) share this one list.
Applies to cc-router v3.0.0 and later.
Design change (v3.0+: Anthropic + OpenAI field superset)
To let one URL satisfy both Anthropic SDKs and OpenAI SDKs / OpenAI Responses clients, cc-router treats /v1/models as the superset of Anthropic /v1/models and OpenAI /v1/models schemas:
| Field | Source protocol | Notes |
|---|---|---|
type: "model" | Anthropic | Anthropic SDK checks for it |
id | Both | Consumed by both |
display_name | Anthropic | Anthropic SDK uses it for display |
created_at (ISO string) | Anthropic | Hard-coded "2026-01-01T00:00:00Z" |
object: "model" | OpenAI | OpenAI SDK checks for it |
created (Unix seconds) | OpenAI | Hard-coded 1767225600 (same moment as created_at) |
owned_by: "cc-router" | OpenAI | OpenAI SDK uses it as the owner label |
Both SDKs use extra: allow and ignore unknown fields, so the same JSON is valid for both sides.
The outer wrapper is also a superset:
| Field | Source protocol |
|---|---|
object: "list" | OpenAI (list wrapper) |
data: [...] | Both |
has_more: false | Anthropic (page wrapper) |
first_id / last_id | Anthropic |
Request
GET /v1/models
- No query parameters, no body
- No authentication (allowlisted alongside
/healthand allOPTIONSpreflights) - Response:
200 OK,Content-Type: application/json
Response
The catalog currently has 30 entries: 16 Anthropic-style + 14 OpenAI-style.
{
"object": "list",
"data": [
{ "type": "model", "id": "model-fable", "display_name": "model-fable", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "model-opus", "display_name": "model-opus", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "model-sonnet", "display_name": "model-sonnet", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "model-haiku", "display_name": "model-haiku", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "claude-fable-5", "display_name": "claude-fable-5", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "claude-opus-4-7", "display_name": "claude-opus-4-7", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "claude-sonnet-4-6", "display_name": "claude-sonnet-4-6", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "claude-haiku-4-5", "display_name": "claude-haiku-4-5", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/claude-fable-5", "display_name": "anthropic/claude-fable-5", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/claude-opus-4-7", "display_name": "anthropic/claude-opus-4-7", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/claude-sonnet-4-6", "display_name": "anthropic/claude-sonnet-4-6", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/claude-haiku-4-5", "display_name": "anthropic/claude-haiku-4-5", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/model-fable", "display_name": "anthropic/model-fable", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/model-opus", "display_name": "anthropic/model-opus", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/model-sonnet", "display_name": "anthropic/model-sonnet", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "anthropic/model-haiku", "display_name": "anthropic/model-haiku", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "gpt-5.6", "display_name": "gpt-5.6", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "gpt-5.5", "display_name": "gpt-5.5", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "gpt-5.4", "display_name": "gpt-5.4", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "gpt-5.4-mini", "display_name": "gpt-5.4-mini", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "gpt-5.6-sol", "display_name": "gpt-5.6-sol", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "gpt-5.6-terra", "display_name": "gpt-5.6-terra", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "gpt-5.6-luna", "display_name": "gpt-5.6-luna", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "openai/gpt-5.6", "display_name": "openai/gpt-5.6", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "openai/gpt-5.5", "display_name": "openai/gpt-5.5", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "openai/gpt-5.4", "display_name": "openai/gpt-5.4", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "openai/gpt-5.4-mini", "display_name": "openai/gpt-5.4-mini", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "openai/gpt-5.6-sol", "display_name": "openai/gpt-5.6-sol", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "openai/gpt-5.6-terra", "display_name": "openai/gpt-5.6-terra", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" },
{ "type": "model", "id": "openai/gpt-5.6-luna", "display_name": "openai/gpt-5.6-luna", "created_at": "2026-01-01T00:00:00Z", "object": "model", "created": 1767225600, "owned_by": "cc-router" }
],
"has_more": false,
"first_id": "model-fable",
"last_id": "openai/gpt-5.6-luna"
}
ID groups
| Group | IDs | Resolves to |
|---|---|---|
| Virtual model short names | model-fable / model-opus / model-sonnet / model-haiku | The slot of the same name |
| Anthropic versioned | claude-fable-5 / claude-opus-4-7 / claude-sonnet-4-6 / claude-haiku-4-5 | model-fable / model-opus / model-sonnet / model-haiku |
anthropic/ prefix (versioned) | anthropic/claude-{fable,opus,sonnet,haiku}-* | Same as above |
anthropic/ prefix (short) | anthropic/model-{fable,opus,sonnet,haiku} | Same as above |
| OpenAI versioned aliases | gpt-5.6 / gpt-5.5 / gpt-5.4 / gpt-5.4-mini | model-fable / model-opus / model-sonnet / model-haiku |
| OpenAI tier aliases | gpt-5.6-sol / gpt-5.6-terra / gpt-5.6-luna | model-fable / model-opus / model-sonnet |
openai/ prefix | The two OpenAI alias groups above with an openai/ prefix, 7 entries | Same as above |
- The list contains example names only; resolution is rule-based, so names not in the list work too — e.g.
claude-opus-4-8andgpt-6-solboth route correctly. See API Overview → Virtual models and aliases for the full rules.- Some clients only display model names in their own protocol’s style. For example, Claude Desktop’s model discovery only recognizes Anthropic-style names and reports “found 16 models” — this is expected.
Differences from the official /v1/models
| Aspect | cc-router | Official Anthropic / OpenAI |
|---|---|---|
| Data source | 30 fixed IDs (hard-coded) | Dynamically returns models accessible to that API key |
created_at / created | Hard-coded 2026-01-01T00:00:00Z / 1767225600 | Each model’s real release timestamp |
| Pagination | has_more is always false; no before_id / after_id | Paginated |
model-fallback | Not in the list (only triggered implicitly) | N/A |
| Fields | Anthropic + OpenAI superset | Each side only its own fields |
A fixed list is returned so that any Anthropic or OpenAI client sees the same available models regardless of which upstream subscriptions cc-router is connected to — they are cc-router’s virtual models. The real routing is decided at POST /v1/messages, POST /v1/responses, or POST /v1/chat/completions time per the virtual-model mapping.
Examples
# List every virtual model ID
curl -s http://127.0.0.1:23456/v1/models | jq '.data[].id'
# Enumerate in OpenAI SDK style
curl -s http://127.0.0.1:23456/v1/models | jq '.data[] | {id, owned_by}'
# Enumerate in Anthropic SDK style
curl -s http://127.0.0.1:23456/v1/models | jq '.data[] | {id, display_name, created_at}'
GET /health
/health is cc-router’s own diagnostic endpoint, usually paired with /v1/models in the allowlist.
GET /health
- No parameters, no body, no auth
- Response:
200 OK,Content-Type: text/plain; charset=utf-8, body is the literal stringok
$ curl -i http://127.0.0.1:23456/health
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
ok
Use cases:
- Startup scripts checking whether cc-router is listening
- Reverse proxy (nginx / caddy) upstream health checks
- Quick browser-based liveness check
/health does not return JSON and does not expose any internal state (version, subscription count, upstream health, etc.). Those flow over Tauri IPC to the UI and are not surfaced via HTTP.