
## Update a provider key

`PATCH /v1/ai/credentials/:id`

Updates the name, the `isDefault` flag, and/or the key itself. If the request includes the `credentials` field — the new key is re-verified with the provider before saving. A key that fails the check is not saved and nothing changes in the database. The `name` and `isDefault` fields are updated without verification.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|----------|
| `id` (path) | string | yes | Key ID from [`GET /v1/ai/credentials`](./list.md) |

## Request fields (body)

| Field | Type | Required | Description |
|------|-----|:-----:|----------|
| `name` | string | no | New key name |
| `isDefault` | boolean | no | Make the key the default for the provider |
| `credentials.apiKey` | string | no | New provider key |
| `credentials.baseUrl` | string | no | New `baseUrl` (only for `custom-openai-compat`) |

At least one field must be passed in the `body`. If `credentials` is passed — it is verified with the provider; on success `lastError` and `lastErrorAt` are reset.

## Examples

### curl — personal key

```bash
curl -X PATCH https://vibecode.bitrix24.com/v1/ai/credentials/cred_abc123def456 \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OpenAI (new name)",
    "credentials": {
      "apiKey": "sk-proj-new-key-..."
    }
  }'
```

### curl — OAuth application

```bash
curl -X PATCH https://vibecode.bitrix24.com/v1/ai/credentials/cred_abc123def456 \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OpenAI (new name)"
  }'
```

### JavaScript — personal key

```javascript
const id = 'cred_abc123def456'
const res = await fetch(`https://vibecode.bitrix24.com/v1/ai/credentials/${id}`, {
  method: 'PATCH',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    credentials: { apiKey: 'sk-proj-new-key-...' },
  }),
})

const { success, data } = await res.json()
if (success) console.log('Key updated at', data.updatedAt)
```

### JavaScript — OAuth application

```javascript
const id = 'cred_abc123def456'
const res = await fetch(`https://vibecode.bitrix24.com/v1/ai/credentials/${id}`, {
  method: 'PATCH',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'OpenAI (production)' }),
})

const { data } = await res.json()
console.log('New name:', data.name)
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` on success |
| `data.id` | string | Key ID |
| `data.providerId` | string | Provider ID |
| `data.provider.slug` | string | Provider system name |
| `data.provider.name` | string | Provider name |
| `data.name` | string | Current key name |
| `data.isDefault` | boolean | Default-key flag |
| `data.lastError` | string \| null | Reset to `null` on a successful key update |
| `data.lastErrorAt` | string \| null | Reset to `null` on a successful key update |
| `data.createdAt` | string | Creation time in `ISO 8601` |
| `data.updatedAt` | string | Last update time in `ISO 8601` |

## Response example

```json
{
  "success": true,
  "data": {
    "id": "cred_abc123def456",
    "providerId": "openai",
    "provider": {
      "slug": "openai",
      "name": "OpenAI"
    },
    "name": "OpenAI (new name)",
    "isDefault": true,
    "lastError": null,
    "lastErrorAt": null,
    "createdAt": "2026-04-15T10:00:00.000Z",
    "updatedAt": "2026-04-27T11:35:00.000Z"
  }
}
```

## Error response example

`422 credential_invalid` — the new key failed verification with the provider:

```json
{
  "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 |
| 400 | `no_key` | `credentials` has no `apiKey` field |
| 400 | `base_url_invalid` | The new `baseUrl` uses a scheme other than `http`/`https` |
| 400 | `base_url_private` | The new `baseUrl` points at a private network |
| 404 | `not_found` | A key with this `id` was not found or does not belong to you |
| 404 | `provider_not_found` | The key's provider was deleted |
| 422 | `credential_invalid` | The new key failed verification with 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](/docs/errors).

## Known specifics

**Verification only when `credentials` changes.** If the request has no `credentials` field (only `name` or `isDefault` are updated) — the provider is not called, and the `lastError`/`lastErrorAt` fields are not reset.

**Empty request body is allowed.** A `PATCH` with an empty `body` (`{}`) returns the current state of the key unchanged — behavior inherited from the Zod schema. Use it to check key availability without touching the data.

**Access to your own keys only.** The endpoint works only with the current user's USER keys. An attempt to update another user's key or a PORTAL key returns `404`.

## See also

- [Key list](./list.md)
- [Connect a key](./create.md)
- [Delete a key](./delete.md)
- [Test a key](./test.md)
