
## Fetch the model catalog

`POST /v1/ai/credentials/:id/fetch-models`

Fetches the list of models from a Custom provider via its `GET /v1/models` endpoint and saves each one as an `AiModel` bound to this key. If the provider does not support `/v1/models` — the operation returns a successful response with a hint to add models manually.

The endpoint works only with the `custom-openai-compat` provider — for other providers the model catalog is fixed and managed by the platform.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|----------|
| `id` (path) | string | yes | Custom key ID from [`GET /v1/ai/credentials`](./list.md) |

No request body is sent.

## Examples

### curl — personal key

```bash
curl -X POST https://vibecode.bitrix24.com/v1/ai/credentials/cred_custom_xyz/fetch-models \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl -X POST https://vibecode.bitrix24.com/v1/ai/credentials/cred_custom_xyz/fetch-models \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const id = 'cred_custom_xyz'
const res = await fetch(`https://vibecode.bitrix24.com/v1/ai/credentials/${id}/fetch-models`, {
  method: 'POST',
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

const { data } = await res.json()
console.log(`Added: ${data.added}, updated: ${data.updated}, marked deprecated: ${data.deprecated}`)
```

### JavaScript — OAuth application

```javascript
const id = 'cred_custom_xyz'
const res = await fetch(`https://vibecode.bitrix24.com/v1/ai/credentials/${id}/fetch-models`, {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { data } = await res.json()
if (data.error === 'PROVIDER_LIST_MODELS_UNAVAILABLE') {
  console.log('The provider does not support GET /v1/models — add models manually:', data.hint)
}
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` |
| `data.added` | number | Number of new `AiModel` records |
| `data.updated` | number | Number of updated records (models that were already in the key's catalog) |
| `data.deprecated` | number | Number of models that were previously fetched but are no longer returned by the provider — their status is automatically changed to `DEPRECATED` |
| `data.error` | string | Only on a provider error: `PROVIDER_LIST_MODELS_UNAVAILABLE` |
| `data.hint` | string | A hint on what to do next, returned on error |
| `data.message` | string | The message from the provider on error |

## Response example

Successful catalog fetch:

```json
{
  "success": true,
  "data": {
    "added": 5,
    "updated": 12,
    "deprecated": 0
  }
}
```

The provider does not support `GET /v1/models` (for example, Minimax):

```json
{
  "success": true,
  "data": {
    "added": 0,
    "updated": 0,
    "deprecated": 0,
    "error": "PROVIDER_LIST_MODELS_UNAVAILABLE",
    "hint": "add models manually: POST /v1/ai/credentials/cred_custom_xyz/models",
    "message": "OpenAI API 404: page not found"
  }
}
```

## Error response example

`400 not_custom_provider` — the key does not belong to a Custom provider:

```json
{
  "success": false,
  "error": {
    "code": "not_custom_provider",
    "message": "fetch-models is only available for custom-openai-compat provider"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `not_custom_provider` | The endpoint works only with the `custom-openai-compat` provider |
| 404 | `not_found` | A key with this `id` was not found or does not belong to you |
| 403 | `scope_missing` | The API key lacks the `vibe:ai` scope |

Full list of common API errors — [Errors](/docs/errors).

Catalog fetch limit: 10 requests per minute (one bucket per portal).

## Known specifics

**Idempotent.** Re-running does not create duplicates: models with an already existing `modelId` are updated (the `name`, `contextLength`, `maxOutputTokens` fields), new ones are added, and those no longer in the provider's catalog get the `DEPRECATED` status (usage history is preserved).

**Prices are zero.** Fetched models default to `inputPrice = 0`, `outputPrice = 0` — BYOK means you pay the provider directly. Platform billing skips such records.

**Alternative on `PROVIDER_LIST_MODELS_UNAVAILABLE`.** If the provider does not return a model catalog — add each model manually via [`POST /v1/ai/credentials/:id/models`](./models-add.md). This is needed for Minimax (`api.minimax.io`), some corporate `vLLM` installations, and other services without `GET /v1/models`.

**The `OpenAiAdapter` filter kicks in.** Under the hood the endpoint uses `GET /v1/models` through `OpenAiAdapter`, which filters responses by the `gpt-` prefix. If your Custom service returns models without this prefix (Minimax `abab6.5-chat`, Cohere, etc.) — `fetch-models` returns `added: 0`. Use [manual registration](./models-add.md).

## See also

- [List a key's models](./models-list.md)
- [Add a model manually](./models-add.md)
- [Delete a key's model](./models-delete.md)
- [Connect a key](./create.md)
