Add a Provider
Add a provider so AIControls can send developer requests to it. For what a provider is, see Providers. To decide which requests it serves, see Add a route.
In Settings → Providers, the Providers tab lists your providers. Add Upstream opens a page with four steps:
| Step | What you set |
|---|---|
| Provider | The provider or vendor. Type in the search box to filter the cards, grouped under Providers and OpenAI-compatible vendors. |
| Connection | Name, URL, the API key or the provider's own credentials, Test Connection, and Model Aliases. |
| Routing | Model Patterns, Static Model List, Live Model Discovery, and Enabled. Model Patterns are the models the provider serves through its own route while it is a member of no route. On a route member, the field shows Set by route with an Edit route button for each route instead. |
| Review | A summary of the upstream. Each row's Edit opens its step. Select Save. |
Picking another provider clears API Key, so a key is never sent to a provider it wasn't entered for, and sets Live Model Discovery to the new provider's default: on for providers that list their models live, such as OpenRouter and Fireworks AI, off otherwise. When you edit an upstream, picking its saved provider again restores its saved setting. Editing a value that Test Connection checked, such as the URL, key, or AWS region, clears the test result.
Next checks the current step before moving on. Editing an upstream opens the same page on Connection: every step can be opened from the step bar, and Save is available on every step. Cancel and Back to LLM Upstreams return to the upstreams table.
- Anthropic
- OpenAI
- Azure OpenAI
- Google Vertex
- Amazon Bedrock
- OpenRouter
- Other vendors
- Go to Settings → Providers → Add Upstream and select Anthropic.
Fill in the upstream fields on the Connection and Routing steps:
Field Value Name Any label, e.g. anthropic-prodAPI Key Your sk-ant-...key from console.anthropic.comURL Leave blank for Anthropic's own API. Point it at a third-party gateway instead to use a service that speaks the same Anthropic Messages wire format (e.g. z.ai's GLM models) — the API key can then be in that gateway's own format instead of sk-ant-...Model Patterns Leave blank to serve the Claude family defaults ( claude-*and related patterns), or list specific model IDs
AIControls supports all Claude models including claude-opus-4-8, claude-sonnet-4-6, and claude-haiku-4-5. New models appear automatically as Anthropic releases them.
The sk-ant-... key format is only enforced when the URL is left blank or points at Anthropic's own API (api.anthropic.com). A custom URL accepts whatever key format that gateway issues.
- Select OpenAI as the provider.
Fill in the upstream fields:
Field Value Name e.g. openai-prodAPI Key Your sk-...key from platform.openai.comOrganization ID Optional — your OpenAI org ID if using multiple orgs
To serve Anthropic Messages clients, such as Claude Code, from this upstream, add a Model Aliases entry that maps each Claude model name your clients request (for example, claude-sonnet-4-6) to an OpenAI model ID (for example, gpt-4o). Streaming and non-streaming requests are both translated. For what AIControls translates and what it rejects, see Cross-format routing.
- Select Azure OpenAI as the provider.
Fill in the upstream fields:
Field Value Name Any label, e.g. azure-foundry-prodURL Your resource endpoint plus /openai, e.g.https://YOUR_RESOURCE.cognitiveservices.azure.com/openaiAPI Key (optional) The resource's key, sent in Azure's api-keyheader. Leave blank to use managed identity (see the note below)Model Patterns Glob(s) matching the deployment name(s), e.g. gpt-4o— the models this provider serves through its own routeStatic Model List The deployment name(s) you created in Azure AI Foundry, e.g. gpt-4o— controls what's advertised via model discovery
This covers Azure OpenAI-family models (e.g. GPT-4o) reached via chat completions — the endpoint format above is specific to that path. If your organization instead routes Claude models through Azure AI Foundry (the Claude Code cloud provider gateway), a different endpoint format applies — check with your AIControls administrator for that setup.
An Azure upstream authenticates with an API key or with Azure AD managed identity (DefaultAzureCredential):
- API key: enter the resource's key in API Key (optional). Find it under Azure Portal → your resource → Keys and Endpoint. AIControls sends it in Azure's
api-keyheader. Test Connection checks the key by listing models at the URL. - Managed identity: leave API Key (optional) blank. Credentials (a service principal's
AZURE_CLIENT_ID/AZURE_TENANT_ID/AZURE_CLIENT_SECRET, or workload identity federation) are configured on the AIControls proxy's environment by your platform team, not in this form. Test Connection isn't available for managed identity.
When you edit an upstream that has a key, a blank API Key (optional) keeps the saved key. To move an upstream from a key to managed identity, delete it and add it again without a key.
Upstreams in config.yaml or Helm values follow the same rule: an azure upstream with apiKey, apiKeyEnv or apiKeyFile sends the key in api-key, and one without a key uses managed identity when auth.type is azure-managed-identity.
- Select Google Vertex as the provider.
Fill in the upstream fields:
Field Value Name Any label, e.g. vertex-prodURL https://aiplatform.googleapis.com, or a regional variant, e.g.https://us-east5-aiplatform.googleapis.comModel Patterns Glob(s) matching Gemini model IDs, e.g. gemini-*— the models this provider serves through its own routeStatic Model List Optional — explicit Gemini model IDs to advertise via model discovery, e.g. gemini-2.5-pro
Vertex upstreams authenticate via Google Application Default Credentials (ADC) — a service account key file, or GKE/GCE Workload Identity — configured on the AIControls proxy's pod environment, not in this form. There is no API key field.
Send requests through the native /vertex/* route (used by CLAUDE_CODE_USE_VERTEX=1 and the Vertex/Gemini SDKs' own request format) — this is the only path that speaks Vertex's native generateContent/streamGenerateContent protocol today. The OpenAI-compatible /v1/chat/completions route can't translate to a google-vertex upstream. A request that routes there fails with a 502, so use the native route for Vertex traffic.
GET /v1/models for a Vertex upstream is served from the Gemini entries in AIControls' cost table, not a live probe against Google — Vertex has no OpenAI-shaped /v1/models endpoint to probe. This means the models listed there track what AIControls has pricing for, not necessarily every Gemini model your GCP project has access to; set Static Model List to advertise a specific model that isn't priced yet — it's always included alongside the cost-table entries, regardless of the Live Model Discovery setting.
- Select Amazon Bedrock as the provider.
Fill in the upstream fields:
Field Value AWS Region e.g. us-east-1— the region where your Bedrock models are enabledIAM Role ARN Role AIControls assumes to sign Bedrock requests, e.g. arn:aws:iam::123456789012:role/MyBedrockRoleInference Profile Which cross-Region profile to invoke: US (default), Europe, Asia Pacific, GovCloud, or Global AWS Region and IAM Role ARN are required; Inference Profile defaults to US. Bedrock upstreams authenticate with IAM (SigV4) — there is no API key field, and the endpoint URL is derived from the region for you.
Grant the role bedrock:InvokeModel scoped to the model and inference-profile ARNs you want to allow. Claude 3.7 and newer can only be invoked through a cross-Region inference profile, so the policy needs inference-profile/ resources as well as foundation-model/ ones — and Global profiles need a third ARN on top. See Prerequisites for policies you can copy.
Model names are translated to the matching Bedrock inference-profile ID for you, so send the short name (claude-sonnet-4-5) from your client. Inference Profile decides which one — set it to match your geography, since the default is US regardless of the region you configured. Requests still go to your configured region; Bedrock does the cross-Region routing itself.
Cost is attributed against the short name, so Bedrock traffic rolls up alongside direct-provider traffic for the same model whichever profile you pick. Use Model Aliases to pin an exact profile ID for a single model — it takes precedence over this setting.
OpenRouter routes to models from many vendors through one key. Models whose ID ends in :free, such as nvidia/nemotron-3.5-lightning:free, need no credits, so you can try AIControls at no cost. See Try AIControls with free models and a public MCP server. You still need a key from your own free OpenRouter account.
- Create a key at openrouter.ai/settings/keys.
- Go to Settings → Providers → Add Upstream and select OpenRouter (free and paid models). The URL fills in as
https://openrouter.ai/api/v1, and Live Model Discovery turns on. - Paste the
sk-or-v1-...key into API Key, and select Test Connection. The test checks the key with OpenRouter, which takes no credits. - Save. Agents send OpenRouter model IDs as they are, such as
nvidia/nemotron-3.5-lightning:freeormeta-llama/llama-3.3-70b-instruct, to either the OpenAI-compatible endpoint (/v1/chat/completions) or the Anthropic endpoint (/v1/messages).
To create the same upstream with the admin API:
curl -X PUT "$YOUR_WORKSPACE_URL/api/v1/llm-upstreams/openrouter?create=true" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\":\"openrouter\",\"provider\":\"openrouter\",\"url\":\"https://openrouter.ai/api/v1\",\"apiKey\":\"$OPENROUTER_API_KEY\",\"enabled\":true,\"modelDiscovery\":true}"
A :free model served by an OpenRouter upstream is priced at $0 in cost reports and budgets unless you add a cost-table row for it. The suffix has no special meaning on any other provider. Other OpenRouter models need cost-table rows, keyed by their full ID; without one, a call is priced at the deliberately high unknown-model rate.
Free models have daily rate limits, and some of their providers log prompts. AIControls makes no data-retention or no-training claim for OpenRouter, so a policy that requires zero data retention denies it. Use free models to try things out, not for production data.
DeepSeek, Moonshot (Kimi), Z.ai (GLM), Fireworks AI, Groq, Cerebras, Together AI, Mistral AI, xAI, Perplexity, Google Gemini, the community vendors (such as Hugging Face, NVIDIA NIM, Cohere, and Sarvam AI), Ollama, vLLM, and any other OpenAI-compatible endpoint are configured by vendor id. AIControls takes the endpoint and host from the vendor catalog.
In the console:
- Go to Settings → Providers → Add Upstream. On the Provider step, type the vendor's name and select its card under OpenAI-compatible vendors, or select Custom OpenAI-compatible for an endpoint that isn't listed.
- The URL fills in from the vendor catalog. For a hosted vendor it is pinned to the vendor's hosts: locked when the vendor has one host, and limited to the catalog's hosts when it has several, such as Moonshot's
api.moonshot.aiandapi.moonshot.cn. An existing OpenRouter or Fireworks AI upstream saved on its own URL, such as a gateway in front of the vendor, keeps that URL editable. The panel below it shows the vendor's endpoints, its catalog models with their prices, the responses that mean its credit ran out, its data-handling defaults, and the request fixes AIControls applies. - Paste the API key. The panel links to the vendor's console, where you create one. Local Ollama needs no key.
- Select Test Connection, then save. Test Connection checks the key against the vendor's model list. A vendor without one, such as Z.ai or Perplexity, can't be tested this way: save the upstream and send a test request instead. An OpenAI-only vendor, such as Groq, starts with Model Patterns set to
groq/*and the vendor's catalog models; edit them to the models you route there.
The Credit / quota column of the upstreams table shows Out of credit for an upstream whose vendor reported exhausted credit or quota in the last 24 hours, with the time of the latest failure, and OK when no out-of-credit or quota failure was recorded in that window. OK doesn't test the key or check the remaining balance. A local upstream shows n/a, and the cell shows a dash while request activity is loading or unavailable. If the vendor catalog can't load, the Provider step says so and lists only the built-in providers.
In the config file or with the admin API:
- Create an API key on the vendor's console, for example platform.deepseek.com or console.groq.com/keys. Local Ollama needs no key.
Add the upstream with its
vendorid. In the config file:llmProxy:upstreams:- name: deepseek-creditsvendor: deepseekapiKeyEnv: DEEPSEEK_API_KEYWith the admin API:
curl -X PUT "$YOUR_WORKSPACE_URL/api/v1/llm-upstreams/deepseek-credits?create=true" \-H "Authorization: Bearer $ADMIN_TOKEN" \-H "Content-Type: application/json" \-d "{\"vendor\":\"deepseek\",\"apiKey\":\"$DEEPSEEK_API_KEY\",\"enabled\":true}"- Leave
providerandurlempty. AIControls sets the provider to the vendor id and the URL to the vendor's endpoint. A URL on any other host is rejected; usevendor: customwith your ownurlfor an endpoint that isn't in the catalog.
To give a vendor that isn't in the catalog its own id, hosts, credit signals, and request fixes, or to change a catalog vendor's entry, add it to an operator vendor catalog file (llmProxy.vendorCatalogFile, or llmProxy.vendorCatalog in the Helm chart). The vendor is then configured by its id like any other. See Add or replace vendors.
Provider names must be unique, and share one name space with routes — adding a provider with a name that already exists is rejected so an existing provider or route is never overwritten by mistake. Editing an existing upstream or pool, such as rotating its API key, keeps working when the route of the same name has the upstream, or one of the pool's upstreams, as a member, as the route converted from it does. Deleting a provider that a route uses is refused with 409; remove it from the route first. Deleting or disabling a provider whose own implicit route an Access Binding grant names is refused with 409 too; change the binding's Via route first. On a deployment whose providers come from the configuration file, saved providers replace the file's upstreams: once a stored route uses a config-file provider, saving the first enabled provider is refused with 409, naming the route, until you remove that provider from the route or save a provider of the same name.
When you add more than one provider for the same models, such as two Anthropic keys or Anthropic and Amazon Bedrock, put them in one route, in the order you want them tried. See Add a route. Two providers of the same family that each serve the same models through their own route tie, and requests either could serve fail with 503 and the code UPSTREAM_AMBIGUOUS.
A provider with no API key and no managed credential has the passthrough credential mode: it forwards the caller's own credential and serves only callers that bring one. Every other provider has the org key mode. See Credential mode.
Add Claude on Google Vertex AI
The google-vertex-anthropic provider serves Claude models from Vertex AI Model Garden. Add it in Settings → Providers, in the config file, or with the admin API. The setup wizard offers it too, under Other — see Other providers. Once the upstream exists, the wizard's Model step offers it as configured, with Google workload identity and its project and region in place of a key — see An upstream that's already set up.
- Enable the Claude models you want in Vertex AI Model Garden for your Google Cloud project, and note the region they're enabled in.
- Give the AIControls proxy Google Application Default Credentials: a service account key file, or GKE/GCE Workload Identity. The service account needs permission to call Vertex AI predictions, such as the Vertex AI User role (
roles/aiplatform.user). Add the upstream.
- Settings
- Config file or API
Go to Settings → Providers → Add Upstream and select Google Vertex (Anthropic Claude), listed under Providers after Google Vertex. On the Connection step:
Field Value Name Any label, e.g. vertex-claudeProject ID The Google Cloud project where Claude is enabled in Vertex AI Model Garden, e.g. my-projectRegion Where Vertex AI runs the model: global (any region with capacity), us-east5, europe-west1, or asia-southeast1 URL Read-only. Built from the project ID and region Model Aliases Optional — map the name your client sends to a Vertex model name, e.g. claude-sonnet-4-5=claude-sonnet-4-5@20250929There's no API Key field and no Test Connection: the upstream uses the proxy's Google credentials. Until Project ID and Region are set, Review shows the URL as From the project ID and region.
The region also sets the upstream's jurisdiction for data-handling policies: a
us-region isUS, aeurope-region isEU, andglobalmeets neither aUSnor anEUrequirement. See Jurisdiction of a Google Vertex upstream.When you edit the upstream, Project ID and Region are filled in from its saved URL. A saved URL in any other form, such as a proxy in front of Vertex AI, is kept as it is, with the two fields empty. Filling them in replaces the URL.
The URL names the project and region and ends at the Anthropic models collection:
https://{region}-aiplatform.googleapis.com/v1/projects/{project}/locations/{region}/publishers/anthropic/modelsFor the
globalregion, use the hostaiplatform.googleapis.com.In
config.yamlor Helm values, setauth.typetogcp-workload-identity:llmProxy:upstreams:- name: vertex-claudeprovider: google-vertex-anthropicurl: https://us-east5-aiplatform.googleapis.com/v1/projects/my-project/locations/us-east5/publishers/anthropic/modelsauth:type: gcp-workload-identitystaticModels:- claude-sonnet-4-5modelAliases:claude-sonnet-4-5: claude-sonnet-4-5@20250929With the admin API, the provider sets the authentication for you:
curl -X PUT "$YOUR_WORKSPACE_URL/api/v1/llm-upstreams/vertex-claude?create=true" \-H "Authorization: Bearer $ADMIN_TOKEN" \-H "Content-Type: application/json" \-d '{"provider":"google-vertex-anthropic","url":"https://us-east5-aiplatform.googleapis.com/v1/projects/my-project/locations/us-east5/publishers/anthropic/models","staticModels":["claude-sonnet-4-5"],"modelAliases":{"claude-sonnet-4-5":"claude-sonnet-4-5@20250929"},"enabled":true}'- Send a test request to
/v1/messagesor/v1/chat/completionswith a model the upstream matches. Test Connection isn't available for this provider, because it uses the proxy's Google credentials.
AIControls sends each request to {url}/{model}:rawPredict, or {url}/{model}:streamRawPredict for streaming, with the model removed from the body and "anthropic_version": "vertex-2023-10-16" added. Use Model Aliases (modelAliases) to map the model name your client sends to a Vertex model name with a version suffix. Vertex has no model-list endpoint, so list the models to advertise on GET /v1/models in Static Model List (staticModels) and leave Live Model Discovery off. count_tokens returns a 501 for this provider. For details, see Claude on Google Vertex AI.
See also
- Add a route — group providers into an ordered failover chain
- Model Routes — how AIControls picks a provider for each request
- Providers
Testing private upstreams
Connection tests connect directly to the configured endpoint and do not follow
HTTP redirects or use environment HTTP proxies. For a private upstream, ask
your self-hosted operator to add its IP or CIDR to proxy.ssrfAllowlist in the
proxy configuration. Use the final endpoint URL rather than a redirect URL.
The same restriction applies to OIDC connectivity probes, OAuth metadata
fetches, Okta discovery, and cross-app token exchange. Permit only the internal
ranges these integrations require; metadata and loopback addresses are blocked
by default.
Cross-app access token endpoints must use HTTPS, including endpoints on allowlisted private networks. An HTTP endpoint is rejected before any client secret or signed assertion is sent.