
## Fetch the model catalog

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

Fetches the list of models from the provider through its adapter and saves each one as an `AiModel` bound to this key — for any provider, standard or Custom. Fetched models are visible and callable only with this key and never enter the shared platform catalog. If the provider does not support catalog loading, the operation returns a successful response with a hint to add models manually. Models can be added manually for keys of any provider.

The endpoint is available for your own USER keys of any provider, including `custom-openai-compat`.

## Parameters

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

The request has no body.

## 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('Could not load the catalog. Check the key and provider availability:', data.message)
}
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` |
| `data` | object | Result of the catalog load: model counters and, when the provider did not return a catalog, the `error`, `hint` and `message` fields |
| `data.added` | number | Number of new `AiModel` records |
| `data.updated` | number | Number of the key's models that were already fetched and came back from the provider again |
| `data.deprecated` | number | Number of the key's models that are no longer returned by the provider — their status is automatically changed to `DEPRECATED` |
| `data.truncated` | boolean | `true` when the provider returned more new models than the key has room for: one key holds at most 1000 models. The models that did not fit were not saved |
| `data.error` | string | On adapter creation or catalog loading failure: `PROVIDER_LIST_MODELS_UNAVAILABLE` (except an HTTP redirect) |
| `data.hint` | string | A hint on what to do next, returned on error |
| `data.message` | string | Diagnostic message about the adapter creation or catalog loading failure |

## Response example

Successful catalog fetch:

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

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

```json
{
  "success": true,
  "data": {
    "added": 0,
    "updated": 0,
    "deprecated": 0,
    "truncated": false,
    "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 no_key` — the saved credential data contains no API key:

```json
{
  "success": false,
  "error": {
    "code": "no_key",
    "message": "No API key in credentials"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `no_key` | The saved credential data contains neither `apiKey` nor `api_key` |
| 400 | `base_url_redirect` | The provider responded with an HTTP redirect; for a Custom key, set `baseUrl` to the final API address |
| 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 Bitrix24 account). The effective value is returned in the `x-ratelimit-limit` header.

## Known specifics

**Idempotent.** Re-running does not create duplicates: the key's existing models are updated (the `name`, `contextLength`, `maxOutputTokens` fields), and new ones are added. The key's models that are no longer in the provider's catalog get the `DEPRECATED` status (usage history is preserved). A model that returns to the provider's catalog gets the `ACTIVE` status again.

**The platform catalog is not affected.** Models are fetched only into your key's catalog: other users and Bitrix24 accounts do not see them, and the operation never creates, enables or changes models in the platform catalog. If a model with the same `modelId` also exists in the platform catalog, your requests to it go through your key.

**At most 1000 models per key.** When the provider returns more new models than the key has room for, the first ones in catalog order are saved and the response carries `truncated: true`. Models that did not fit are not treated as gone: only models missing from the provider's catalog get the `DEPRECATED` status. To free up room, delete models you do not need via [`DELETE /v1/ai/credentials/:credId/models/:modelRowId`](./models-delete.md).

**Model capabilities come from the platform catalog.** When a model with the same `modelId` exists in the platform catalog, the new key model inherits its capabilities (`capabilities`) and reasoning settings: calls with `response_format`, embeddings and reasoning work the same as with the platform model. The price is not copied.

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

**Loading failure `PROVIDER_LIST_MODELS_UNAVAILABLE`.** This code means adapter creation or catalog loading failed (except an HTTP redirect); it does not establish that the catalog is unsupported. Check `data.message`, the key, and provider availability. If you have confirmed that the provider does not support a model catalog, add each model manually via [`POST /v1/ai/credentials/:id/models`](./models-add.md).

**All listed models are kept.** The model list request uses every model in the provider list, including OpenAI IDs without the `gpt-` prefix.

**Model list request limits.** They are shared by `available-models`, `fetch-models` and connection: 20 seconds including all retries and pages, up to 5 MiB per response before JSON parsing, 1000 models and 10 pages. A repeated cursor stops pagination. Only one such request runs per Bitrix24 account at a time, at most 10 per minute. Incomplete lists never change absent models to `DEPRECATED`.

When a limit cuts the list short, the response contains `truncated: true`. Preview without saving: [available-models](./available-models.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 provider key](./create.md)