For AI agents: markdown of this page — /docs-content-en/search/credentials/create.md documentation index — /llms.txt

Add a key

POST /v1/search/credentials

Saves a BYOK key for the chosen provider for the current user. After it is added, calls to POST /v1/search and POST /v1/research with that provider do not charge Ꝟ — you are billed directly by the provider.

Before saving, the server makes a trial call to the provider with the supplied key. If the provider rejects the key — 400 INVALID_CREDENTIAL is returned and the record is not created. Only after a successful check is the key encrypted and saved. After saving, the original value cannot be returned through the API — the output contains only the mask <first 5>********<last 4>.

Request fields (body)

Field Type Req. Default Description
provider string yes One of the BYOK providers: tavily, brave, exa, you-com, linkup, perplexity, jina, z-ai. bitrix-search is not accepted through v1
apiKey string yes A token from the chosen provider. Tavily — format tvly-…, Brave — a subscription token from the Brave dashboard, the rest — a token from the corresponding provider's dashboard
name string yes A custom label for the key, shown in the list. From 1 to 64 characters
isDefault boolean no false Make it default for the provider. Requests to POST /v1/search and POST /v1/research without the provider field will go through this key

Examples

curl — personal key

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

curl — OAuth app

Terminal
curl -X POST https://vibecode.bitrix24.com/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": "My Tavily",
    "isDefault": true
  }'

JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.com/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: 'My Tavily',
    isDefault: true,
  }),
})

const cred = await res.json()
console.log('Key created:', cred.id)

JavaScript — OAuth app

javascript
const res = await fetch('https://vibecode.bitrix24.com/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: 'My Tavily',
    isDefault: true,
  }),
})

const cred = await res.json()

Response fields

Field Type Description
id string Identifier of the created key. Passed to DELETE /v1/search/credentials/:id and POST /v1/search/credentials/:id/test
provider string Provider identifier: one of the eight BYOK providers
scope string Visibility level. When created through v1 — always USER
name string Label from the request
maskedKey string Mask <first 5>********<last 4>
isDefault boolean Whether the key became default for the provider
createdAt string Creation date in ISO 8601 format

Response example

201 — key created:

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

Error response example

400 — the provider rejected the key during the pre-check:

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

400 — an attempt to add 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'"
  }
}

Other situations are listed in the error table below.

Errors

HTTP Code Description
400 INVALID_CREDENTIAL The provider rejected the key during the pre-check. The record is not saved. The message contains the reason — for example, Upstream HTTP 401 for a revoked Tavily key, Upstream HTTP 422 for an invalid Brave subscription token
400 INVALID_REQUEST apiKey not specified, name empty or longer than 64 characters, provider not from the list of eight BYOK providers
401 MISSING_API_KEY The X-Api-Key header is missing
401 INVALID_API_KEY Invalid API key
401 UNAUTHORIZED The request goes through a vibe_app_… key without Authorization: Bearer <session_token>
403 SCOPE_DENIED The key lacks the vibe:search scope
404 PROVIDER_NOT_FOUND A provider with this identifier does not exist or is disabled
429 RATE_LIMITED The overall request limit is exceeded
500 INTERNAL_ERROR Internal server error

The full list of common API errors — Errors.

Known specifics

One default key per provider. When a new key is created with isDefault: true, all other USER keys of the same provider automatically stop being default. The previous key stays in the system — it can be used through an explicit provider in POST /v1/search or deleted.

Several keys of one provider without a default. When a user has several USER keys of one provider, none is marked isDefault: true, and only provider is specified in POST /v1/search — the most recent one by createdAt is taken. For predictable behavior, mark the desired key as default.

The key is verified with the provider before saving. The server makes a trial call to the chosen provider with the supplied apiKey. The record is created only on a positive result; in that case the lastVerifiedAt field is immediately filled with the current date. This closes the class of errors "a key chosen as default that the provider has already revoked" and removes the need for a separate POST /v1/search/credentials/:id/test step right after creation. The test endpoint is needed later — to re-verify an already-saved key after rotation at the provider.

Network errors before reaching the provider are masked as INVALID_CREDENTIAL. If the verification request did not reach the provider (DNS, a network timeout between Vibecode and the provider), the user sees the same 400 INVALID_CREDENTIAL with a message about the reason. This is a safe default — not to save a key whose status is not confirmed. Retry after a short time.

See also