Providers & BYOK
Connect your own provider account once, then call its models through the AI Gateway as provider/model.
Overview
A provider is one set of credentials for one AI vendor, stored for your organization. With Bring Your Own Key (BYOK), requests that name a provider's model go to your account at that vendor, and the vendor bills you for them.
- Console: open Providers in the sidebar, under Build.
- API: the
/v1/providersendpoints below. - CLI:
backbone providers, see CLI.
API keys you store are encrypted at rest and never returned: no response on this page contains apiKey.
Tier Availability
BYOK is part of the Team, Business and Enterprise plans. On these plans the console shows Providers in the sidebar, and a request that routes to your own provider is billed by that provider, and its model charge does not count against your plan's usage. On Starter, or without a plan, the sidebar item is hidden; use the platform models instead.
Calling Your Models
Name a BYOK model as <prefix>/<model>. The prefix picks the provider type; everything after the first / is passed to the provider unchanged.
openai/gpt-5.1
azure-openai/my-gpt-deployment
anthropic/claude-sonnet-4-5-20250929
xai/grok-4
mistral/mistral-large-latest
ollama/llama3
A name without a / is a platform model and never touches your providers. The same naming works everywhere a model is accepted: chat completions, the Responses API, extraction, transcription and agents.
One provider per type
The prefix names a provider type, not one of your providers. Configure at most one provider of each type per organization; to switch accounts, update the provider's API key instead of adding a second one. The API refuses a second provider of a type you already have: POST /v1/providers answers 409 and names the type.
What goes wrong, and how the gateway answers:
| Situation | Response |
|---|---|
Unknown prefix, e.g. nope/gpt-5.1 | 400, the message lists the valid prefixes |
| Known prefix, but no provider of that type configured | 404 Provider not configured. Please check your provider settings. |
| Platform model name that does not exist | 404, the message lists the available platform models |
Supported Provider Types
| Provider | provider value | Prefix | config keys |
|---|---|---|---|
| OpenAI | OPENAI | openai | baseUrl (optional), organizationId (optional, your OpenAI organization), useResponsesApi (optional, true or false) |
| Azure OpenAI | AZURE_OPENAI | azure-openai | endpoint (required, https://), apiVersion (optional), extendedPromptCacheRetention (optional, true or false) |
| Anthropic | ANTHROPIC | anthropic | baseUrl (optional), version (optional, default 2023-06-01) |
| xAI | XAI | xai | baseUrl (optional) |
| Mistral | MISTRAL | mistral | baseUrl (optional) |
| Ollama | OLLAMA | ollama | baseUrl (required, your server, e.g. http://ollama.internal:11434) |
- Every
baseUrlmust start withhttp://orhttps://. Leave it out to use the vendor's default endpoint; set it for a proxy. - For Azure OpenAI, the part after the prefix is your deployment name, not the model name.
- For Ollama, the server must be reachable from 2kw.ai, and the models are the ones pulled on it. Ollama needs no key: leave
apiKeyout. useResponsesApi: truemakes 2kw.ai talk to OpenAI through the Responses API instead of chat completions.extendedPromptCacheRetention: trueasks Azure to keep this row's prompt cache for 24 hours instead of the few minutes it defaults to, for every deployment on this row named exactlygpt-4.1,gpt-5.1orgpt-5.4— other deployments on the same row are untouched. Azure stores key/value tensors of the prompt prefix on GPU-local storage on your own Azure account for up to 24 hours after last use — inside the data zone for Data Zone deployments, inside the region for Regional deployments; Microsoft makes no such statement for Global deployments.gpt-5.5deployments use extended retention by default whatever this setting says. The deployment name must match the model it serves, or Azure refuses the call.- Blank
configvalues are dropped before the provider is saved.
Google Vertex AI
The API schema lists VERTEX_AI, but Vertex AI is not supported: creating or testing a provider of that type answers 400.
Test a Connection
POST /v1/providers/test
Checks credentials before you save them, or re-checks a saved provider. Nothing is stored. Whether the credentials work or not, the answer is 200: read success. A providerId that does not exist answers 404, and a provider type that is not supported answers 400.
curl -X POST https://api.2kw.ai/v1/providers/test \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_api_key" \
-d '{
"provider": "AZURE_OPENAI",
"apiKey": "your-azure-key",
"config": { "endpoint": "https://my-resource.openai.azure.com" }
}'
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Yes | Provider type, e.g. OPENAI |
config | object | Yes | The same config you would save |
apiKey | string | No | Key to test. Leave it out and send providerId to test a saved provider's stored key |
providerId | string | No | A saved provider whose stored key is used when apiKey is empty |
Success
{
"success": true,
"models": ["my-gpt-deployment", "my-embedding-deployment"]
}
Failure
{
"success": false,
"message": "Authentication failed: 401"
}
On success, models lists what the credentials can reach; for Azure OpenAI these are your deployment names. On failure, message says why: a missing key, the HTTP status the vendor answered, or the connection error.
Create a Provider
POST /v1/providers
curl -X POST https://api.2kw.ai/v1/providers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_api_key" \
-d '{
"name": "Production OpenAI",
"provider": "OPENAI",
"apiKey": "sk-proj-...",
"config": {}
}'
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name, 1–255 characters, unique within the organization |
provider | string | Yes | Provider type from the table above |
apiKey | string | Yes, except for OLLAMA | The vendor API key. Stored encrypted, never returned |
config | object | Yes | Type-specific settings; {} when you need none |
Answers 201 with the provider:
{
"id": "0b8e6f3c-...",
"name": "Production OpenAI",
"provider": "OPENAI",
"config": {},
"organizationId": "org_...",
"createdAt": "2026-09-27T10:15:00Z",
"lastModifiedAt": "2026-09-27T10:15:00Z"
}
The response also carries version and aliases; treat them as informational.
A config that breaks the rules for its type (an Azure provider without endpoint, a baseUrl without http:// or https://, a useResponsesApi or extendedPromptCacheRetention that is not true or false) is refused with 400 and the message says what to fix. A name the organization already uses answers 409, as does a second provider of the same type. A 4xx will not succeed on retry: fix the request.
Update a Provider
PATCH /v1/providers/{id}
Send only what changes:
namerenames the provider; a name another provider of the organization already uses answers409.apiKeyreplaces the stored key; leave it out to keep the current one.configreplaces the whole storedconfig, it is not merged. Send every key you want to keep.providercannot be changed. To move to another type, create a new provider and delete the old one.
curl -X PATCH https://api.2kw.ai/v1/providers/0b8e6f3c-... \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_api_key" \
-d '{ "apiKey": "sk-proj-new-key" }'
Read Providers
GET /v1/providers
A page of providers. Query parameters: search (matches the name, case-insensitive), page, size and sort.
GET /v1/providers/all
Every provider of the organization as a plain array, without paging.
GET /v1/providers/{id}
One provider. An id that does not exist answers 404.
List Available Models
GET /v1/providers/models
The platform models first, then your providers' models under their provider/model names, fetched live from each vendor.
{
"object": "list",
"data": [
{ "id": "gpt-5.1", "object": "model", "owned_by": "system" },
{ "id": "openai/gpt-5.1", "object": "model", "owned_by": "openai" },
{ "id": "anthropic/claude-sonnet-4-5-20250929", "object": "model", "owned_by": "anthropic" }
]
}
owned_by is system for platform models and the prefix for yours. Use the id as the model of a request.
The list is a convenience, not the full set of names you can call:
- Azure OpenAI deployments are not listed. Call them by deployment name;
POST /v1/providers/testshows the names. - OpenAI is filtered to chat models (
gpt-,o1-,o3-,o4-,chatgpt-); fine-tunes and other models are left out. - A vendor that cannot be reached, or refuses the key, contributes no models instead of failing the call.
A model missing from this list can still work. For embedding models of one provider, see Which embedding models fit. A knowledge base no longer needs a provider of yours at all: it can embed through the platform's built-in embedding models.
Delete a Provider
DELETE /v1/providers/{id}
Answers 204. From then on, every request that names this provider's prefix answers 404 until you configure a provider of that type again, so move agents, prompts and schemas that use it to another model first.
Permissions
| Operation | Role needed |
|---|---|
| List, get, list models | Viewer, Member, Admin or Owner |
| Create, update, test | Member, Admin or Owner |
| Delete | Admin or Owner |
An API key acts with the role it was created with.