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 | Required | Default | Description |
|---|---|---|---|---|
Fieldprovider |
Typestring | Requiredyes | Default— | DescriptionOne of the BYOK providers: tavily, brave, exa, you-com, linkup, perplexity, jina, z-ai. bitrix-search is not accepted through v1 |
FieldapiKey |
Typestring | Requiredyes | Default— | DescriptionA 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 |
Fieldname |
Typestring | Requiredyes | Default— | DescriptionA custom label for the key, shown in the list. From 1 to 64 characters |
FieldisDefault |
Typeboolean | Requiredno | Defaultfalse |
DescriptionMake 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": "YOUR_TAVILY_API_KEY",
"name": "My Tavily",
"isDefault": true
}'
curl — OAuth application
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": "YOUR_TAVILY_API_KEY",
"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: 'YOUR_TAVILY_API_KEY',
name: 'My Tavily',
isDefault: true,
}),
})
const cred = await res.json()
console.log('Key created:', cred.id)
JavaScript — OAuth application
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: 'YOUR_TAVILY_API_KEY',
name: 'My Tavily',
isDefault: true,
}),
})
const cred = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
Fieldid |
Typestring | DescriptionIdentifier of the created key. Passed to DELETE /v1/search/credentials/:id and POST /v1/search/credentials/:id/test |
Fieldprovider |
Typestring | DescriptionProvider identifier: one of the eight BYOK providers |
Fieldscope |
Typestring | DescriptionVisibility level. When created through v1 — always USER |
Fieldname |
Typestring | DescriptionLabel from the request |
FieldmaskedKey |
Typestring | DescriptionMask <first 5>********<last 4> |
FieldisDefault |
Typeboolean | DescriptionWhether the key became default for the provider |
FieldcreatedAt |
Typestring | DescriptionCreation 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 |
|---|---|---|
| HTTP400 | CodeINVALID_CREDENTIAL |
DescriptionThe 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 |
| HTTP400 | CodeINVALID_REQUEST |
DescriptionapiKey not specified, name empty or longer than 64 characters, provider not from the list of eight BYOK providers |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is missing |
| HTTP401 | CodeINVALID_API_KEY |
DescriptionThe key is not recognized — no such key exists on the platform |
| HTTP401 | CodeUNAUTHORIZED |
DescriptionThe request goes through a vibe_app_… key without Authorization: Bearer <session_token> |
| HTTP403 | CodeSCOPE_DENIED |
DescriptionThe key lacks the vibe:search scope |
| HTTP404 | CodePROVIDER_NOT_FOUND |
DescriptionA provider with this identifier does not exist or is disabled |
| HTTP429 | CodeRATE_LIMITED |
DescriptionThe overall request limit is exceeded |
| HTTP500 | CodeINTERNAL_ERROR |
DescriptionInternal 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.