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
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
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
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
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:
{
"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:
{
"error": {
"code": "INVALID_CREDENTIAL",
"message": "Upstream HTTP 401"
}
}
400 — an attempt to add bitrix-search:
{
"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
- Your own keys (BYOK) — subsection overview
- List your keys —
GET /v1/search/credentials - Delete a key —
DELETE /v1/search/credentials/:id - Test a key —
POST /v1/search/credentials/:id/test - Search (POST /v1/search) — BYOK key selection cascade
- Providers — which engines accept BYOK
- Errors — API error code reference