
## Загрузить каталог моделей

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

Загружает список моделей у Custom-провайдера через его эндпоинт `GET /v1/models` и сохраняет каждую как `AiModel`, привязанную к этому ключу. Если провайдер не поддерживает `/v1/models` — операция возвращает успешный ответ с подсказкой добавить модели вручную.

Эндпоинт работает только с провайдером `custom-openai-compat` — для остальных провайдеров каталог моделей фиксирован и управляется платформой.

## Параметры

| Параметр | Тип | Обяз. | Описание |
|----------|-----|:-----:|----------|
| `id` (path) | string | да | ID Custom-ключа из [`GET /v1/ai/credentials`](./list.md) |

Тело запроса не передаётся.

## Примеры

### curl — личный ключ

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

### curl — OAuth-приложение

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

### JavaScript — личный ключ

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

const { data } = await res.json()
console.log(`Добавлено: ${data.added}, обновлено: ${data.updated}, помечено устаревшими: ${data.deprecated}`)
```

### JavaScript — OAuth-приложение

```javascript
const id = 'cred_custom_xyz'
const res = await fetch(`https://vibecode.bitrix24.tech/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('Провайдер не поддерживает GET /v1/models — добавьте модели вручную:', data.hint)
}
```

## Поля ответа

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | Всегда `true` |
| `data.added` | number | Количество новых `AiModel`-записей |
| `data.updated` | number | Количество обновлённых записей (модели, которые уже были в каталоге ключа) |
| `data.deprecated` | number | Количество моделей, которые ранее были загружены, но больше не возвращаются провайдером — их статус автоматически меняется на `DEPRECATED` |
| `data.error` | string | Только при ошибке провайдера: `PROVIDER_LIST_MODELS_UNAVAILABLE` |
| `data.hint` | string | Подсказка по дальнейшим действиям при ошибке |
| `data.message` | string | Сообщение от провайдера при ошибке |

## Пример ответа

Успешная загрузка каталога:

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

Провайдер не поддерживает `GET /v1/models` (например, 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"
  }
}
```

## Пример ответа при ошибке

`400 not_custom_provider` — ключ принадлежит не Custom-провайдеру:

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

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `not_custom_provider` | Эндпоинт работает только с провайдером `custom-openai-compat` |
| 404 | `not_found` | Ключ с таким `id` не найден или не принадлежит вам |
| 403 | `scope_missing` | API-ключу не хватает скоупа `vibe:ai` |

Полный список общих ошибок API — [Ошибки](/docs/errors).

Лимит загрузки каталога: 10 запросов в минуту (единый бакет на портал).

## Известные особенности

**Идемпотентно.** Повторный запуск не создаёт дубликатов: модели с уже существующим `modelId` обновляются (поля `name`, `contextLength`, `maxOutputTokens`), новые добавляются, ушедшие из каталога провайдера получают статус `DEPRECATED` (история использования сохраняется).

**Цены — нулевые.** Загруженные модели по умолчанию имеют `inputPrice = 0`, `outputPrice = 0` — BYOK означает, что вы платите провайдеру напрямую. Платформенный биллинг такие записи пропускает.

**Альтернатива при `PROVIDER_LIST_MODELS_UNAVAILABLE`.** Если провайдер не отдаёт каталог моделей — добавьте каждую модель вручную через [`POST /v1/ai/credentials/:id/models`](./models-add.md). Это нужно для Minimax (`api.minimax.io`), некоторых корпоративных `vLLM`-инсталляций и других сервисов без `GET /v1/models`.

**Срабатывает фильтр `OpenAiAdapter`.** Эндпоинт под капотом использует `GET /v1/models` через `OpenAiAdapter`, который фильтрует ответы по префиксу `gpt-`. Если ваш Custom-сервис возвращает модели без этого префикса (Minimax `abab6.5-chat`, Cohere и др.) — `fetch-models` вернёт `added: 0`. Используйте [ручную регистрацию](./models-add.md).

## Смотрите также

- [Список моделей ключа](./models-list.md)
- [Добавить модель вручную](./models-add.md)
- [Удалить модель ключа](./models-delete.md)
- [Подключить ключ](./create.md)
