#Добавить ключ

POST /v1/search/credentials

Сохраняет BYOK-ключ выбранного провайдера для текущего пользователя. После добавления вызовы `POST /v1/search` и `POST /v1/research` с этим провайдером не списывают Ꝟ — оплата идёт напрямую с вашего аккаунта у поставщика.

Перед сохранением сервер делает пробный вызов к провайдеру с присланным ключом. Если провайдер отклоняет ключ — возвращается 400 INVALID_CREDENTIAL, запись не создаётся. Только после успешной проверки ключ шифруется и сохраняется. После сохранения исходное значение через API не вернуть — в выдаче только маска <первые 5>********<последние 4>.

#Поля запроса (body)

Поле Тип Обяз. По умолч. Описание
provider string да Один из BYOK-провайдеров: tavily, brave, exa, you-com, linkup, perplexity, jina, z-ai. bitrix-search через v1 не принимается
apiKey string да Токен у выбранного провайдера. Tavily — формат tvly-…, Brave — токен подписки из кабинета Brave, остальные — токен из кабинета соответствующего поставщика
name string да Произвольная подпись ключа для отображения в списке. От 1 до 64 символов
isDefault boolean нет false Сделать дефолтным для провайдера. Запросы к POST /v1/search и POST /v1/research без поля provider пойдут через этот ключ

#Примеры

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

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/search/credentials \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "tavily",
    "apiKey": "tvly-abc123def456",
    "name": "Мой Tavily",
    "isDefault": true
  }'

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

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/search/credentials \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "tavily",
    "apiKey": "tvly-abc123def456",
    "name": "Мой Tavily",
    "isDefault": true
  }'

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

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    provider: 'tavily',
    apiKey: 'tvly-abc123def456',
    name: 'Мой Tavily',
    isDefault: true,
  }),
})

const cred = await res.json()
console.log('Создан ключ:', cred.id)

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

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/search/credentials', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    provider: 'tavily',
    apiKey: 'tvly-abc123def456',
    name: 'Мой Tavily',
    isDefault: true,
  }),
})

const cred = await res.json()

#Поля ответа

Поле Тип Описание
id string Идентификатор созданного ключа. Передаётся в `DELETE /v1/search/credentials/:id` и `POST /v1/search/credentials/:id/test`
provider string Идентификатор провайдера: один из восьми BYOK-провайдеров
scope string Уровень видимости. При создании через v1 — всегда USER
name string Подпись из запроса
maskedKey string Маска <первые 5>********<последние 4>
isDefault boolean Стал ли ключ дефолтным для провайдера
createdAt string Дата создания в формате ISO 8601

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

201 — ключ создан:

JSON
{
  "id": "cmol3pnk5001fo70zefbwb6dl",
  "provider": "tavily",
  "scope": "USER",
  "name": "Мой Tavily",
  "maskedKey": "tvly-********f456",
  "isDefault": true,
  "createdAt": "2026-04-30T06:26:51.653Z"
}

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

400 — провайдер отклонил ключ при предварительной проверке:

JSON
{
  "error": {
    "code": "INVALID_CREDENTIAL",
    "message": "Upstream HTTP 401"
  }
}

400 — попытка добавить bitrix-search:

JSON
{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "provider: Invalid enum value. Expected 'tavily' | 'brave' | 'exa' | 'you-com' | 'linkup' | 'perplexity' | 'jina' | 'z-ai', received 'bitrix-search'"
  }
}

Остальные ситуации перечислены в таблице ошибок ниже.

#Ошибки

HTTP Код Описание
400 INVALID_CREDENTIAL Провайдер отклонил ключ при предварительной проверке. Запись не сохранена. Сообщение содержит причину — например, Upstream HTTP 401 для отозванного ключа Tavily, Upstream HTTP 422 для неверного токена подписки Brave
400 INVALID_REQUEST Не указан apiKey, name пустой или длиннее 64 символов, provider не из списка восьми BYOK-провайдеров
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
404 PROVIDER_NOT_FOUND Провайдер с таким идентификатором отсутствует или отключён
429 RATE_LIMITED Превышен общий лимит запросов
500 INTERNAL_ERROR Внутренняя ошибка сервера

Полный список общих ошибок API — Ошибки.

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

Дефолтный ключ — один на провайдер. При создании нового ключа с isDefault: true все остальные USER-ключи того же провайдера автоматически перестают быть дефолтными. Прежний ключ остаётся в системе — его можно использовать через явный provider в `POST /v1/search` или удалить.

Несколько ключей одного провайдера без дефолта. Когда у пользователя несколько USER-ключей одного провайдера, ни один не помечен isDefault: true, и в `POST /v1/search` указан только provider — берётся самый поздний по createdAt. Для предсказуемого поведения отметьте нужный ключ как дефолтный.

Ключ проверяется у провайдера до сохранения. Сервер делает пробный вызов выбранного провайдера с переданным apiKey. Запись создаётся только при положительном результате; в этом случае поле lastVerifiedAt сразу заполняется текущей датой. Это закрывает класс ошибок «дефолтным выбран ключ, который провайдер уже отозвал» и устраняет необходимость отдельного шага `POST /v1/search/credentials/:id/test` сразу после создания. Тестовый эндпоинт нужен позже — для перепроверки уже сохранённого ключа после ротации у поставщика.

Сетевые ошибки до провайдера маскируются под INVALID_CREDENTIAL. Если запрос проверки не дошёл до провайдера (DNS, тайм-аут сети между Вайбкод и поставщиком), пользователь увидит ту же 400 INVALID_CREDENTIAL с сообщением о причине. Это безопасный дефолт — не сохранять ключ, статус которого не подтверждён. Повторите попытку через короткое время.

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