# List models

Source: https://platform.lyrouter.com/ai_gateway/docs/models/en
Last updated: 2026-10-22

Returns every name the current API key can put in `model`: the models enabled in the key's workspace that the guardrail model policies allow this key to call, plus the enabled virtual models (`@vmodel/<name>`) and `lyrouter/auto`. The response uses OpenAI's model list format, which suits clients that fill a model picker or check at startup that their configured models are available. The gateway answers this endpoint itself: it does not call the upstream, is not billed and is not written to the log list.

`GET /v1/models`

## Authentication

Send your API key in a request header:

```text
Authorization: Bearer <API Key>
```

`Bearer` is case-sensitive. You can use `x-api-key: <API Key>` instead; when both are present, only `Authorization` is read. Create API keys on the workspace's **API Keys** page; the list is built from the key's workspace and the model policies that apply to the key. See [Base URLs and authentication](https://platform.lyrouter.com/ai_gateway/docs/call-gateway/en).

## Headers

| Header | Required | Description |
| --- | --- | --- |
| `Authorization` or `x-api-key` | Yes | Use either one; see "Authentication" above |

A GET request has no body, so `Content-Type` is not needed.

## Query parameters

None. The list is not paginated and all entries are returned at once; query parameters sent with the request are ignored.

## Request examples

**Request examples**

cURL:
```bash
curl https://api.lyrouter.com/v1/models \
  -H "Authorization: Bearer $LYROUTER_API_KEY"
```

Python:
```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LYROUTER_API_KEY"],
    base_url="https://api.lyrouter.com/v1",
)

for model in client.models.list():
    print(model.id)
```

Node.js:
```js
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.LYROUTER_API_KEY,
  baseURL: "https://api.lyrouter.com/v1",
});

for await (const model of client.models.list()) {
  console.log(model.id);
}
```

## Response

A successful request returns the model list with `Content-Type: application/json`; an error returns an `error` object. The 401 below means the request carried no API key; the 503 means the gateway temporarily cannot read the workspace's model configuration.

**Response examples**

200:
```json
{
  "object": "list",
  "data": [
    {
      "id": "deepseek/deepseek-v4-flash",
      "object": "model",
      "created": 1791964800,
      "owned_by": "workspace",
      "display_name": "DeepSeek V4 Flash",
      "context_length": 131072,
      "max_output_tokens": 8192,
      "api_types": ["chat_completions", "responses"],
      "input_modalities": ["text"],
      "output_modalities": ["text"],
      "supported_params": ["temperature", "top_p", "max_tokens", "tools", "tool_choice", "response_format", "stream"]
    },
    {
      "id": "google/gemini-3-pro-image",
      "object": "model",
      "created": 1791964800,
      "owned_by": "workspace",
      "display_name": "Gemini 3 Pro Image",
      "api_types": ["images"],
      "input_modalities": ["text", "image"],
      "output_modalities": ["image"]
    },
    {
      "id": "lyrouter/auto",
      "object": "model",
      "created": 1791964800,
      "owned_by": "workspace"
    },
    {
      "id": "@vmodel/support-bot",
      "object": "model",
      "created": 1791964800,
      "owned_by": "workspace"
    }
  ]
}
```

401:
```json
{
  "error": {
    "message": "missing credentials",
    "type": "invalid_request_error"
  }
}
```

503:
```json
{
  "error": {
    "message": "Workspace model projection is unavailable",
    "type": "service_unavailable",
    "code": "workspace_model_projection_unavailable"
  }
}
```

Entries come in a fixed order: specific models first, sorted alphabetically by model ID; then `lyrouter/auto`; and finally virtual models, sorted by name.

| Field | Type | Description |
| --- | --- | --- |
| `object` | string | Always `list` |
| `data[].id` | string | The name to put in the request's `model`; use it as is |
| `data[].object` | string | Always `model` |
| `data[].created` | integer | Unix time (seconds) when this response was generated; the same for every entry, and not the model's release date |
| `data[].owned_by` | string | Always `workspace`; it does not indicate the model vendor or the provider |
| `data[].display_name` | string | The model's display name in the model marketplace, suitable for showing in a UI; calls still use `id` |
| `data[].context_length` | integer | Context length (tokens) |
| `data[].max_output_tokens` | integer | Maximum output length (tokens) |
| `data[].api_types` | string[] | The endpoints the model declares support for, such as `chat_completions`, `responses`, `embeddings`, `rerank`, `images` and `videos`; values can also be finer-grained operations such as `images_edits` |
| `data[].input_modalities` / `output_modalities` | string[] | Input and output modalities, such as `text` and `image` |
| `data[].supported_params` | string[] | The request parameters the model declares support for; for reference only, the gateway does not trim chat request parameters based on it |

- `display_name` and the fields after it appear only on specific models, and only when the model catalog has that information; a missing field or an empty array (such as `"api_types": []`) means "not declared", not "not supported".
- `lyrouter/auto` and virtual models have only the four fields `id`, `object`, `created` and `owned_by`; the model they actually call is decided at routing time.
- The response is always in the OpenAI format, without fields such as `has_more` and `first_id` from the Anthropic Models API; applications using the Anthropic SDK should send a plain HTTP request and read `data[].id`.

### Which names the list includes

| Category | Listed | Condition |
| --- | --- | --- |
| Models under Workspace models in the model marketplace | Listed | Filtered by the guardrail model policies that apply to this key: models a policy denies, or that are not on its allow list, are not listed |
| Models under Available and Needs connection | Not listed | They appear only after they are enabled in this workspace or connected through BYOK |
| Enabled virtual models | Listed, as `@vmodel/<name>` | Not filtered by model policies; disabled or deleted virtual models are not listed |
| `lyrouter/auto` | Always listed | Not filtered by model policies, and not affected by the Auto candidate scope |

### How it relates to the model marketplace

Both cover the same scope, the models enabled in the current workspace; they differ in who they are for:

| | Model marketplace | `GET /v1/models` |
| --- | --- | --- |
| Audience | Members signed in to the console | Programs holding an API key |
| Model policies | Restricted providers show "Member access restricted" | Restricted models are simply not listed |
| Granularity | Each model lists status and price per provider | One entry per model, no provider shown |
| Virtual models, Auto | Not shown | Listed |
| Display name | Card title | `display_name` field |

When a model is available in the model marketplace but missing from the list, a guardrail model policy usually restricts this key; ask the current Account Owner to check [Model access](https://platform.lyrouter.com/ai_gateway/docs/authorization/en). The public model marketplace shows every model on the platform, which is not the same as what a given workspace can call.

## Common uses

### Filling a client's model picker

Show `display_name` and submit `id`. To list only chat models, keep entries whose `api_types` contains `chat_completions` (look for `responses` in clients that use Responses), and keep entries without `api_types`, or whose `api_types` is an empty array, together with `lyrouter/auto` and virtual models:

```python
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["LYROUTER_API_KEY"], base_url="https://api.lyrouter.com/v1")

def is_chat(model):
    extra = model.model_extra or {}
    api_types = extra.get("api_types")
    return not api_types or "chat_completions" in api_types

options = [
    {"value": m.id, "label": (m.model_extra or {}).get("display_name") or m.id}
    for m in client.models.list()
    if is_chat(m)
]
```

`display_name`, `api_types` and similar fields are not standard OpenAI fields, so the OpenAI Python SDK puts them in `model_extra`; the Node.js SDK reads them directly as object properties.

For commands that filter embedding and rerank models by `api_types`, see [Create embeddings](https://platform.lyrouter.com/ai_gateway/docs/embeddings/en) and [Rerank documents](https://platform.lyrouter.com/ai_gateway/docs/rerank/en).

### Checking configured models at startup

Request the list once when the application starts and confirm that the model IDs in your configuration file appear in `data[].id`. When one is missing, report "model not enabled or not permitted"; that is easier to troubleshoot than waiting for the first call to return 403. You can cache the list for a few minutes; there is no need to request it before every call.

## Gateway behavior

- **Answered by the gateway**: the gateway builds the list from the workspace configuration, does not call the upstream provider and does not bill the request; model discovery requests are not written to the log list.
- **Listed does not mean callable**: when the gateway builds the list, it does not check whether provider credentials currently work, nor the balance, budgets or quotas. A listed model can still return 503 because of an invalid credential, or 402 because of an insufficient balance; see [Unavailable models](https://platform.lyrouter.com/ai_gateway/docs/unavailable/en).
- **Virtual models and Auto are checked at call time**: when the model they actually select is denied by a model policy, the call returns 403 `Request blocked by guardrail policy`.
- **Check endpoint support separately**: the list covers chat, embedding, image and other kinds of models. If you only need models for a chat UI, filter by `api_types` or `output_modalities`; see "Common uses" above.
- **Configuration changes apply within seconds**: enabling or disabling a model in the model marketplace, enabling or disabling a virtual model, or changing a model policy shows up in the list within a few seconds.

## Common errors

Error responses take the form `{"error":{"message":"...","type":"...","code":"..."}}`; only some errors include `code`.

| Status code | `error.message` | `error.code` | Cause and fix |
| --- | --- | --- | --- |
| 401 | `missing credentials` | — | No API key was sent; see [401 / 403: authentication and access](https://platform.lyrouter.com/ai_gateway/docs/auth-errors/en) |
| 401 | `invalid api key` | — | The gateway cannot find this key: it was copied incompletely, or the key was deleted, disabled or has expired; see [401 / 403: authentication and access](https://platform.lyrouter.com/ai_gateway/docs/auth-errors/en) |
| 402 | `subscription expired; renew to continue` | — | The account's subscription has expired and its grace period is over; ask the current Account Owner to renew |
| 403 | `api key expired` | — | The key has expired |
| 403 | `your IP address is not allowed` | — | The request's egress IP is not on the key's IP allowlist |
| 503 | `Workspace model projection is unavailable` | `workspace_model_projection_unavailable` | The gateway temporarily cannot read the workspace's model configuration; this is a platform-side problem, so retry later |

- A method other than GET, or a misspelled path (for example `/v1/models/` with a trailing `/`), returns 404 with the body `{"error_msg":"404 Route Not Found"}`, with no outer `error`.
- All error codes are listed in [Errors and request identifiers](https://platform.lyrouter.com/ai_gateway/docs/errors/en).

## FAQ

### The list contains only `lyrouter/auto` and no models. What should I do?

**Answer:** The workspace has not enabled any models yet, or a guardrail model policy denies this key every model. In the workspace's **Model marketplace**, confirm that Workspace models is not empty, then ask the current Account Owner to check the model policies; see [Choosing a model](https://platform.lyrouter.com/ai_gateway/docs/choose/en) and [Model access](https://platform.lyrouter.com/ai_gateway/docs/authorization/en).

### The same model is offered by several providers. Why does the list have only one entry?

**Answer:** Model IDs are independent of providers, and each model has exactly one ID. At call time the gateway picks a provider as described in [Channels and routing](https://platform.lyrouter.com/ai_gateway/docs/routing/en); the provider that actually served a call is shown under Provider in the request log.

### Can I use an `id` from the list directly on image or video endpoints?

**Answer:** For specific models, yes, provided `api_types` or `output_modalities` shows that the model supports that endpoint. `lyrouter/auto` and `@vmodel/<name>` return 403 `Model is not available in the model plaza` on image and video endpoints: `lyrouter/auto` works only with Chat Completions, Anthropic Messages and Responses; besides these three, virtual models can also be used with [Create embeddings](https://platform.lyrouter.com/ai_gateway/docs/embeddings/en) and [Rerank documents](https://platform.lyrouter.com/ai_gateway/docs/rerank/en), provided that every model in the virtual model's list is a matching embedding or rerank model.
