For AI agents: markdown of this page — /docs-content-en/ai/credentials/create.md documentation index — /llms.txt
Connect a provider key
POST /v1/ai/credentials
Connects a new provider key to your user (USER scope). The key is automatically verified with the provider before saving: a key that fails the check is not saved. One user can connect only one key per provider.
Request fields (body)
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
providerId |
string | yes | — | Provider ID. List: GET /v1/ai/providers |
name |
string | yes | — | Arbitrary key name shown in the list |
credentials.apiKey |
string | yes | — | Provider key (e.g. sk-... for OpenAI) |
credentials.baseUrl |
string | conditional | — | Required for custom-openai-compat. Format: https://api.example.com/v1. Only http/https, private networks forbidden |
isDefault |
boolean | no | false |
Use this key as the default for the provider |
Examples
curl — personal key
curl -X POST https://vibecode.bitrix24.com/v1/ai/credentials \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"providerId": "openai",
"name": "My personal OpenAI",
"credentials": {
"apiKey": "sk-proj-..."
},
"isDefault": true
}'
curl — OAuth application
curl -X POST https://vibecode.bitrix24.com/v1/ai/credentials \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"providerId": "openai",
"name": "My personal OpenAI",
"credentials": {
"apiKey": "sk-proj-..."
},
"isDefault": true
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/ai/credentials', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
providerId: 'openai',
name: 'My personal OpenAI',
credentials: { apiKey: 'sk-proj-...' },
isDefault: true,
}),
})
const { success, data } = await res.json()
if (success) console.log('Key connected, ID:', data.id)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/ai/credentials', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
providerId: 'openai',
name: 'My personal OpenAI',
credentials: { apiKey: 'sk-proj-...' },
}),
})
const { data } = await res.json()
console.log('ID:', data.id)
Connecting a Custom OpenAI-Compatible service
For an arbitrary OpenAI-compatible service (Minimax, Cerebras, Cohere, a corporate vLLM/Ollama, etc.) use providerId: cprv_custom_seed and be sure to specify baseUrl:
curl -X POST https://vibecode.bitrix24.com/v1/ai/credentials \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"providerId": "cprv_custom_seed",
"name": "Corporate service",
"credentials": {
"apiKey": "sk-corp-...",
"baseUrl": "https://llm.example.com/v1"
}
}'
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.id |
string | Unique ID of the created key |
data.providerId |
string | Provider ID |
data.provider.slug |
string | Provider system name |
data.provider.name |
string | Provider name |
data.name |
string | Key name from the request |
data.isDefault |
boolean | Default-key flag |
data.createdAt |
string | Creation time in ISO 8601 |
data.updatedAt |
string | Last update time in ISO 8601 |
Response example
HTTP status 201 Created:
{
"success": true,
"data": {
"id": "cred_abc123def456",
"providerId": "openai",
"provider": {
"slug": "openai",
"name": "OpenAI"
},
"name": "My personal OpenAI",
"isDefault": true,
"createdAt": "2026-04-27T11:30:00.000Z",
"updatedAt": "2026-04-27T11:30:00.000Z"
}
}
Error response example
422 credential_invalid — the key failed verification with the provider:
{
"success": false,
"error": {
"code": "credential_invalid",
"message": "OpenAI API 401: Incorrect API key provided"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | invalid_request |
The body schema is violated (missing required fields) |
| 400 | no_key |
credentials has no apiKey field |
| 400 | base_url_invalid |
baseUrl uses a scheme other than http/https, or is malformed |
| 400 | base_url_private |
baseUrl points at a private network or does not resolve to an IP address via DNS |
| 404 | provider_not_found |
A provider with this providerId does not exist or is disabled |
| 409 | already_exists |
A key for this provider is already connected — use PATCH /v1/ai/credentials/:id |
| 422 | credential_invalid |
The key failed verification with the provider. The message contains details from the provider |
| 422 | provider_geoblocked |
The provider rejected the key check based on our server's region. Connect your own proxy or switch to OpenRouter. The response carries a suggestions field |
| 403 | scope_missing |
The API key lacks the vibe:ai scope |
Full list of common API errors — Errors.
Key creation limit: 10 requests per minute (one bucket per portal — all the portal's keys share it).
Known specifics
Verification before saving. The key is verified with the provider via verify() — an HTTP request to GET /v1/models or (if the provider does not support models) to POST /v1/chat/completions with a minimal body. The verification timeout is 10 seconds. For an invalid key, nothing is saved to the database.
SSRF protection for the Custom provider. The baseUrl for custom-openai-compat must pass a check: private networks are forbidden (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16), IPv6 link-local and ULA, IPv4-mapped IPv6. Only http:///https:// schemes are accepted.
Error message sanitized. The error text from the provider is truncated to 200 characters, and URLs are replaced with the placeholder [URL] — this protects against accidental leakage of internal addresses into the client's logs.