
## Список своих ключей

`GET /v1/search/credentials`

Возвращает все BYOK-ключи текущего пользователя со скрытым телом ключа. Сервер хранит ключи в зашифрованном виде — вернуть исходное значение нельзя, в выдаче только маска.

## Параметры

Параметров нет.

## Примеры

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

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.tech/v1/search/credentials
```

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

```bash
curl \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.tech/v1/search/credentials
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

const { credentials } = await res.json()
credentials.forEach((c) => {
  console.log(`${c.provider} · ${c.maskedKey} · ${c.isDefault ? 'дефолтный' : 'обычный'}`)
})
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { credentials } = await res.json()
```

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

| Поле | Тип | Описание |
|------|-----|---------|
| `credentials` | array | Массив BYOK-ключей пользователя. Может быть пустым |
| `credentials[].id` | string | Идентификатор ключа. Передаётся в [`DELETE /v1/search/credentials/:id`](/docs/search/credentials/delete) и [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test) |
| `credentials[].provider` | string | Идентификатор провайдера: один из восьми BYOK (`tavily`, `brave`, `exa`, `you-com`, `linkup`, `perplexity`, `jina`, `z-ai`) |
| `credentials[].scope` | string | Уровень видимости ключа. Через v1 возвращается только `USER` |
| `credentials[].name` | string | Произвольная подпись ключа |
| `credentials[].maskedKey` | string | Маска `<первые 5>********<последние 4>`. Полный ключ через API получить нельзя |
| `credentials[].isDefault` | boolean | Считается дефолтным для провайдера. Берётся, когда в [`POST /v1/search`](/docs/search/run) поле `provider` опущено |
| `credentials[].lastVerifiedAt` | string \| null | Дата последней успешной проверки через [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test) в формате ISO 8601 |
| `credentials[].lastError` | string \| null | Текст последней ошибки проверки. `null`, если последняя проверка прошла успешно или проверок не было |
| `credentials[].createdAt` | string | Дата добавления ключа в формате ISO 8601 |

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

```json
{
  "credentials": [
    {
      "id": "cmol3pnk5001fo70zefbwb6dl",
      "provider": "tavily",
      "scope": "USER",
      "name": "Мой Tavily",
      "maskedKey": "tvly-********a1b2",
      "isDefault": true,
      "lastVerifiedAt": "2026-04-30T06:30:00.000Z",
      "lastError": null,
      "createdAt": "2026-04-30T06:26:51.653Z"
    }
  ]
}
```

Пустой список:

```json
{ "credentials": [] }
```

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

401 — для OAuth-ключа не передан `Authorization: Bearer`:

```json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "No user context."
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|---------|
| 401 | `MISSING_API_KEY` | Отсутствует заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Неверный API-ключ |
| 401 | `UNAUTHORIZED` | Запрос идёт через ключ `vibe_app_…` без `Authorization: Bearer <session_token>` |
| 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `vibe:search` |
| 429 | `RATE_LIMITED` | Превышен общий лимит запросов |
| 500 | `INTERNAL_ERROR` | Внутренняя ошибка сервера |

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

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

**Восстановление утерянного ключа.** Получить исходное значение из системы нельзя — единственный путь после потери токена удалить запись через [`DELETE /v1/search/credentials/:id`](/docs/search/credentials/delete) и добавить ключ заново.

**`lastVerifiedAt` обновляется только через `test`.** Обычные поисковые запросы через [`POST /v1/search`](/docs/search/run) дату не двигают — даже если фактическое использование ключа прошло успешно. Для свежей метки вызывайте [`POST /v1/search/credentials/:id/test`](/docs/search/credentials/test).

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

- [Свои ключи (BYOK)](/docs/search/credentials)
- [Добавить ключ](/docs/search/credentials/create)
- [Удалить ключ](/docs/search/credentials/delete)
- [Проверить ключ](/docs/search/credentials/test)
- [Поиск (POST /v1/search)](/docs/search/run)
- [Ошибки](/docs/errors)
