Upsert AI Provider
Creates or updates an AI provider's configuration and the AI features it serves. The saved configuration is used by the next AI call; nothing needs activating.
api_key is nullable on purpose. You cannot read the key back, so a save that leaves it out keeps the stored one:
- omitted or
nullkeeps the stored key (the first save of a provider must carry one); - a non-empty string replaces it;
- an empty string is refused: a provider cannot be saved without a key.
A stored key is only sent to the endpoint it was saved for. Changing base_url to another origin while keeping the stored key is refused with 10015 naming api_key: send the key again. An empty base_url counts as the vendor's own endpoint.
Defaults. An empty base_url is saved as the vendor's endpoint (https://api.anthropic.com for claude, https://api.openai.com for openai), a timeout of 0 as 60 seconds and a max_tokens of 0 as 1024. The response shows the saved values.
Features. features is the full list and replaces the stored one; omitting it clears it. Turning is_enabled off keeps the features, so turning it back on restores the same scope. Note that is_enabled is written as sent: omitting it disables the provider.
Platform owner only. The caller's node must be the platform root node; any other caller is refused with 403 / 10005.
Required permission: ai-provider:update
Request
PUT /v2/admin/ai-providers/{provider}
Parameters
| Name | Type | In | Description |
|---|---|---|---|
provider | string | path | Required. Provider key: claude or openai |
Headers
| Name | Description |
|---|---|
Authorization | Required. Bearer <access_token> |
Content-Type | Required. application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
api_key | string | null | Conditional | Vendor API key. Required on the first save; null keeps the stored key afterwards |
base_url | string | No | API base URL. Empty means the vendor's own endpoint |
model | string | Yes | Model used for text features (e.g. claude-sonnet-4-5, gpt-4o) |
image_model | string | Conditional | Model used for tokenization_image (e.g. gpt-image-1). Required when features contains tokenization_image; may be stored ahead of that |
timeout | integer | No | Request timeout in seconds, 0 or greater. 0 means 60 |
max_tokens | integer | No | Maximum reply length in tokens, 0 or greater. 0 means 1024 |
is_enabled | boolean | No | Master switch. Omitted means false |
features | array of string | No | AI features this provider serves: tokenization_suggestion, support_assistant, tokenization_image. Each at most once. tokenization_image only on openai |
Example
curl --request PUT \
--url '{{baseUrl}}/v2/admin/ai-providers/openai' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"api_key": "<openai_api_key>",
"base_url": "",
"model": "gpt-4o",
"image_model": "gpt-image-1",
"timeout": 0,
"max_tokens": 0,
"is_enabled": true,
"features": ["tokenization_suggestion", "tokenization_image"]
}'
Response
200 OK with the saved provider, masked as on List AI Providers.
{
"provider": "openai",
"base_url": "https://api.openai.com",
"model": "gpt-4o",
"image_model": "gpt-image-1",
"timeout": 60,
"max_tokens": 1024,
"is_enabled": true,
"features": ["tokenization_suggestion", "tokenization_image"],
"api_key_set": true,
"api_key_last4": "Zk8w",
"configured": true,
"created_at": "2026-11-09T11:31:56.218Z",
"updated_at": "2026-11-09T11:31:56.218Z"
}
Errors
| Status | Code | Description |
|---|---|---|
| 400 | 10015 | Validation failed (model missing, negative timeout or max_tokens) — see details. Also (with details naming api_key) a stored key that would move to a new endpoint |
| 400 | 79001 | Unsupported provider key (domain 79) |
| 400 | 79002 | Unknown feature, or a feature listed twice (domain 79) |
| 400 | 79004 | No API key: the first save carries none, or api_key is an empty string (domain 79) |
| 400 | 79008 | The provider cannot serve a listed feature (tokenization_image on claude) (domain 79) |
| 400 | 79009 | tokenization_image listed without an image_model (domain 79) |
| 403 | 10005 | The caller is not the platform owner (domain 2) |
See Errors for the error format and common codes.