> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xpander.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# AI vendors

> The model providers xpander speaks to, where their keys live, and what changes when you bring your own key.

xpander runs any model, commercial or your own, through the [AI gateway](https://docs.xpander.ai/run/integrations/ai-gateway.md). The provider sets which harness a new agent starts on, and whether calls cost credits or run on your own key.

![Diagram](https://docs.xpander.ai/images/diagrams/run-integrations-ai-vendors-0bf570ca.svg)

## Providers

| Provider | Key | Notes |
| - | - | - |
| Anthropic | `ANTHROPIC_API_KEY` | Default for Claude Code. Baked default model: Fable 5.1 (`claude-fable-5-1`) |
| OpenAI | `AGENTS_OPENAI_API_KEY` | Default for Codex. Baked default: `gpt-6-astra` |
| Amazon Bedrock | `AWS_BEARER_TOKEN_BEDROCK`, or keyless through the pods' AWS identity | Fable- and Mythos-class Anthropic models need the account's data-retention opt-in per region, or Bedrock answers `400 data retention mode 'default' is not available for this model` |
| Google | `GOOGLE_API_KEY` | |
| Fireworks, Nebius, OpenRouter, Helicone | `FIREWORKS_API_KEY`, `NEBIUS_API_KEY`, `OPENROUTER_API_KEY`, `HELICONE_API_KEY` | OpenCode takes any `<provider>/<model>` slot the proxy routes |
| Your own OpenAI-compatible runtime (vLLM, Ollama, NVIDIA NIM) | None, or whatever the runtime requires | Required on Air-Gapped. Register it with **Add provider** ([steps](#add-a-custom-provider)) |

## Where keys live

Every agent model call, including Bedrock and per-agent endpoints, goes through the [LLM Gateway](https://docs.xpander.ai/run/llm-gateway.md). The key comes from the first of:

| Order | Where | How |
| - | - | - |
| 1 | **An agent-level credential** | On one agent |
| 2 | **An organization-level key per provider** | **Platform > AI governance > Models**: **Use your own key…** on a listed provider, or **Add provider** for your own endpoint. The **Providers** table shows **Connected** or **Needs a key** |
| 3 | **The install's keys** on a self-hosted cluster | Chart values `secrets.static.<provider>ApiKey`, or a Kubernetes secret referenced with `envFromSecretKeys` |

To set an install key:

```bash theme={"dark"}
helm upgrade xpander xpander/xpander --namespace xpander --reset-then-reuse-values \
  --set secrets.static.anthropicApiKey=<KEY> --timeout 5m
```

* `--reset-then-reuse-values` needs Helm 3.14 or later. It keeps your values and applies the chart's defaults for the rest.
* The LLM Gateway is always on self-hosted, so every provider your agents use needs a key in place 2 or 3. Otherwise the call is refused with a message naming the missing key.
* A key named by an environment variable on agent-controller (custom provider, agent or organization default model) never reads the install's own credentials. A name on the reserved list reads as no key ([reserved key names](https://docs.xpander.ai/self-hosted/hybrid.md#key-names-read-from-an-environment-variable)).
* Pods restart on their own when a secret changes. The `xpander-static` secret has a Helm keep policy: if a key is not picked up after an upgrade, patch the secret and restart `xpander-agent-worker`. Full mapping: [Hybrid: managing LLM API keys](https://docs.xpander.ai/self-hosted/hybrid.md#managing-llm-api-keys).

![Add Anthropic key panel with API key, Name and Description fields and an Add Anthropic key button](https://mintcdn.com/xpanderai-099931d1/wqIIXSsh0kqA2hZ_/images/verify/llm-add-key-anthropic-1.png?fit=max\&auto=format\&n=wqIIXSsh0kqA2hZ_\&q=85\&s=aab93b66f04150b4602a5d0a77506d7e)

Use your own key on a built-in provider: the API key, its name and an optional description. Shown with sample data.

## Credits against your own keys

Calls on keys xpander provides are charged in credits. Calls on a key you brought, agent or organization level, never are.

Hybrid agents never use xpander's keys: every provider needs a key in the organization or on the install (`secrets.static`), and Claude Code on Bedrock needs your own Bedrock auth. See [Licenses and who pays](https://docs.xpander.ai/run/llm-gateway/which-key-pays.md).

## Provider setup on a self-hosted install

Claude Code speaks to Anthropic, Codex to OpenAI, and OpenCode to any `<provider>/<model>` slot the proxy routes. Credentials live **only on the Agent Controller**.

### Anthropic direct

Put an Anthropic API key on the controller. It egresses to `api.anthropic.com`. To use your own gateway, set `LLM_PROXY_ANTHROPIC_BASE_URL`.

### Anthropic on Amazon Bedrock

Claude Code runs Anthropic models on Bedrock through the proxy's `amazon_bedrock` leg. The controller resolves AWS auth in this order, and no executor sees it:

| Method | Controller environment | Notes |
| - | - | - |
| Bearer token | `AWS_BEARER_TOKEN_BEDROCK` (+ `BEDROCK_REGION` / `AWS_REGION`) | Relayed as-is, no signing. The simplest option |
| Assume role | `BEDROCK_ASSUME_ROLE_ARN` (+ `BEDROCK_ASSUME_ROLE_EXTERNAL_ID`, `_SESSION_NAME`) | STS credentials, self-refreshing, SigV4 signed |
| Static keys | `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` (/ `AWS_SESSION_TOKEN`) | SigV4 signed |
| Default credential chain | `AGENT_GATEWAY_BEDROCK_DEFAULT_CHAIN=true` (default) | IRSA / EKS Pod Identity / instance profile, SigV4 signed |

| Install | Setting |
| - | - |
| Air-Gapped | No public Bedrock. Point `LLM_PROXY_AMAZON_BEDROCK_BASE_URL` at a VPC (PrivateLink) Bedrock runtime endpoint with the matching region, or leave Bedrock off. The chart exposes this under `global.llm.bedrock`: `region`, `bearerTokenSecret` (a Secret you create with a Bedrock API key), `assumeRoleArn` and `assumeRoleExternalId` (STS), and `baseUrl` (the VPC endpoint). Leave the token and role empty to use the pod's credential chain (EKS Pod Identity or IRSA). |
| Hybrid | Set the same variables on the Agent Controller through the chart's env values. |

> [!WARNING]
>
> **Fable- and Mythos-class Anthropic models on Bedrock need the account's data-retention opt-in, per region.**
>
> * With the default mode, every call fails with `400 data retention mode 'default' is not available for this model`. Accepted modes: `provider_data_share`, or `aws_review` where offered.
> * There is no console switch. Per region, call `PUT https://bedrock.<region>.amazonaws.com/data-retention` with `{"mode": "provider_data_share"}` (SigV4-signed, IAM action `bedrock:PutAccountDataRetention`), for every region a `global.` inference profile can route to.
> * The first call after the change can still fail while it propagates. Retry first.
> * It applies to **whichever AWS account signs the call**. An organization's own stored Bedrock key wins over the install's credential, so that account needs the opt-in too.
> * Older Anthropic models need no opt-in, which is why the error looks model-specific.

> [!NOTE]
>
> **Bedrock in a Hybrid deployment needs your own credentials:** a Bedrock key or role under **Platform > AI governance > Models**, or the cluster's own AWS identity. The account also needs the opt-in above. To use an IAM role instead of a key, see [Amazon Bedrock with an IAM role](https://docs.xpander.ai/run/integrations/bedrock-iam-role.md).

> [!NOTE]
>
> The keyless methods apply to the proxy on the Agent Controller. The `agent-worker` service has its own constraint on keyless Bedrock: see [Amazon Bedrock: key vs IAM](https://docs.xpander.ai/self-hosted/hybrid.md#amazon-bedrock-keyless-iam-or-api-key).

## Add a custom provider

Register any OpenAI-compatible endpoint (vLLM, Ollama, NVIDIA NIM) once under **Platform > AI governance > Models > Add provider**. Same steps: [Custom endpoints](https://docs.xpander.ai/run/llm-gateway/providers-and-keys.md#custom-endpoints).

**1. Name it**

Enter a **Name**. The **ID (used in API calls)** is derived from it and fixed once added.

**2. Set the protocol and address**

**Protocol**: **OpenAI-compatible**. **Base URL**: the address as the pods reach it, for example `http://vllm.<namespace>.svc.cluster.local:8000/v1`.

| Install | Allowed base URL |
| - | - |
| Hybrid or Air-Gapped | Private addresses work. Metadata and link-local addresses are refused. |
| xpander cloud | A public `https` address only. Private, loopback or cluster addresses are refused ([Custom endpoints](https://docs.xpander.ai/run/llm-gateway/providers-and-keys.md#custom-endpoints)). |

**3. Choose the API key**

**No key (local or unauthenticated server)**, **Use an existing key**, or **Create a new key**.

**4. Test and add models**

**Test connection** reports **Reachable** and lists the endpoint's models. A model that accepts function calls carries a `tools` badge. **Add** the models agents may use, then **Add provider**.

**5. Choose the organization's models**

In the provider's **Keys and models…**, tick the models the organization may use. Prices are optional (**Edit model** > **Price per 1M tokens (USD, optional)**). They track spend only and are never charged. A model with no price reads as zero spend.

![Add provider panel with Name, ID (used in API calls), Protocol OpenAI-compatible, Base URL, API key options No key, Use an existing key and Create a new key, and a Models section with Test connection and Add model](https://mintcdn.com/xpanderai-099931d1/wqIIXSsh0kqA2hZ_/images/verify/lab-llm-add-custom-provider.png?fit=max\&auto=format\&n=wqIIXSsh0kqA2hZ_\&q=85\&s=f97a39aaefcc0a88989cc41d8796722f)

Add provider: name and ID, protocol, base URL, the API key choice, and Test connection under Models. Shown with sample data.

### Use a custom provider

* `POST /v1/agents` accepts only built-in providers in `model_provider`. A custom ID gets `422`.
* Pick a custom provider per conversation in the composer's **Harness and model** popover (**Claude Code**, **Codex**, **OpenCode**).
* **Agent readiness** in **Keys and models…** shows whether a harness works with the model, from the last **Test model** run.
* A local model needs a context window well above the prompt xpander composes. Worked example: [Air-Gapped: a worked vLLM setup](https://docs.xpander.ai/self-hosted/airgap.md#a-worked-vllm-setup-on-eks-auto-mode).
* With no `/responses` route on the endpoint, the gateway sends Codex calls as chat completions.

## Which harness and model a new agent gets

A create that names a runtime, provider, model or harness settings is honored as written. Otherwise it is **defaulted**, the same way on cloud, Hybrid and Air-Gapped:

1. **The organization's default LLM** picks the CLI:

   | Organization default LLM | CLI |
   | - | - |
   | Anthropic | Claude Code, on that model |
   | Amazon Bedrock with an Anthropic model id | Claude Code on Bedrock |
   | OpenAI | Codex |
   | Any other provider the LLM proxy routes | OpenCode, with that `<provider>/<model>` slot |

   No default, or a provider no CLI runs, falls through.
2. **The install's default knobs** (env on the `agents` and `agent-controller` services, the chart values below on Air-Gapped).
3. **The baked defaults**: Claude Code on Anthropic direct with Fable 5.1 (`claude-fable-5-1`), Codex on `gpt-6-astra`, OpenCode on `anthropic/claude-opus-5`.

So a fresh Air-Gapped install with no default LLM creates Claude Code agents on **Fable 5.1 over Anthropic direct**, and needs an Anthropic key on the controller or Bedrock set as the default (with the opt-in above). Changing defaults later does not touch existing agents.

| Deployment | Knob | Effect |
| - | - | - |
| Air-Gapped | `global.harness.defaultModels.{claudeCode,codex,opencode,xpander}` (rendered as `XPANDER_HARNESS_DEFAULT_MODEL_<CLI>` on `agent-controller` and the `agents` Deployment) | The model a defaulted agent gets when the org has no default LLM. Name models your endpoint serves. `claudeCode` and `codex` take a bare model id. `opencode` and `xpander` take a `<provider>/<model>` slot. A Bedrock inference-profile id in `claudeCode` (for example `us.anthropic.claude-sonnet-4-6`) implies the provider. An explicit `agents.env` / `agent-controller.env` entry wins |
| Air-Gapped | `global.harness.defaultProviders.claudeCode` (rendered as `XPANDER_HARNESS_DEFAULT_PROVIDER_CLAUDE_CODE` on the `agents` Deployment) | Empty = Anthropic direct. `amazon_bedrock` sends defaulted Claude Code agents to Bedrock through `global.llm.bedrock` |
| Hybrid | none in the chart | The `agents` service runs in xpander cloud, so defaulted Claude Code agents run on **Anthropic direct**. Set the org default LLM to change that. The controller needs credentials for whichever provider your agents use |

**Claude Code on Bedrock on Air-Gapped needs both harness defaults:** `global.harness.defaultProviders.claudeCode: amazon_bedrock` and `global.harness.defaultModels.claudeCode: <Bedrock model id>`. Without them, the first turn fails with `503 no anthropic credential configured for harness agents`, even when the organization's default model is on Bedrock.

## Model access per group

**Who may use it…** under **Platform > AI governance > Models** sets each group's models. A model outside the group's list is hidden from the picker, and a run that names it is refused.

![Access: Amazon Bedrock panel with Organization and the Default, Design, Engineering and Sales groups, each set to All models](https://mintcdn.com/xpanderai-099931d1/wqIIXSsh0kqA2hZ_/images/verify/llm-model-access-group-1.png?fit=max\&auto=format\&n=wqIIXSsh0kqA2hZ_\&q=85\&s=914c1402d04975b325607f7ff9206134)

Who may use it on a provider: the organization, then each group, with the models each may use. Shown with sample data.

## Next steps

> **[Connect Bedrock with an IAM role](https://docs.xpander.ai/run/integrations/bedrock-iam-role.md)**
>
> No long-lived keys.

> **[Add a custom endpoint](https://docs.xpander.ai/run/llm-gateway/providers-and-keys.md#custom-endpoints)**
>
> An OpenAI-compatible runtime.

> **[See who pays for a call](https://docs.xpander.ai/run/llm-gateway/which-key-pays.md)**
>
> Credits and your own keys.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.