# Your own AI keys

> Add your key from a model's provider once, under the name agents read it by, and every agent in every one of your machines works with it - while the key itself never enters a machine.

Add your key from a model's provider once, under the name agents read it by, and every agent in every one of your machines works with it: no sign-in screen, no paste box. The key itself never enters a machine.

wm:

```sh
$ wm secrets set ANTHROPIC_API_KEY
Value of ANTHROPIC_API_KEY (not shown as you type):
Set ANTHROPIC_API_KEY, an AI key: on every machine. Sent only to api.anthropic.com. The key never enters a machine.
```

Python:

```python
key = client.secrets.set("ANTHROPIC_API_KEY", os.environ["MY_ANTHROPIC_KEY"])
print(key.every_machine, key.outside.hosts)  # True ['api.anthropic.com']
```

TypeScript:

```ts
const key = await client.secrets.set("ANTHROPIC_API_KEY", process.env.MY_ANTHROPIC_KEY);
console.log(key.every_machine, key.outside.hosts); // true [ 'api.anthropic.com' ]
```

curl:

```sh
curl -X PUT https://api.wheelmachine.ai/v1/secrets/ANTHROPIC_API_KEY \
  -H "Authorization: Bearer $WHEELMACHINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"value\": \"$MY_ANTHROPIC_KEY\"}"
```

In the dashboard, the **Secrets** page has an **AI keys** part first: a row for each provider, with **Add**, **Replace** and **Remove**. To choose the model each agent starts on, from your keys' own lists, see [Choosing models](https://docs.wheelmachine.ai/models.html).

## How it works

A machine holds a placeholder in the key's place, under the key's name: in the environment of its commands, its terminals, its SSH sessions and its agents. When a program in the machine calls the provider's API over HTTPS, the real key is added to the request on its way out - for the provider's own hosts alone. The program works as it would with the key itself; the machine never has it.

## The names

A secret set under one of these names is an AI key. The names are the ones agents and the providers' own libraries read.

| Provider | Name | Sent only to |
|---|---|---|
| Anthropic | `ANTHROPIC_API_KEY` | api.anthropic.com |
| OpenAI | `OPENAI_API_KEY` | api.openai.com, us.api.openai.com, eu.api.openai.com |
| Gemini | `GEMINI_API_KEY`, `GOOGLE_API_KEY` | generativelanguage.googleapis.com |
| OpenRouter | `OPENROUTER_API_KEY` | openrouter.ai |
| DeepSeek | `DEEPSEEK_API_KEY` | api.deepseek.com |
| xAI | `XAI_API_KEY` | api.x.ai, us.api.x.ai |
| Mistral AI | `MISTRAL_API_KEY` | api.mistral.ai |
| Groq | `GROQ_API_KEY` | api.groq.com |
| Together AI | `TOGETHER_API_KEY` | api.together.ai, api.together.xyz |
| Fireworks AI | `FIREWORKS_API_KEY` | api.fireworks.ai |
| Perplexity | `PERPLEXITY_API_KEY` | api.perplexity.ai |
| Cohere | `COHERE_API_KEY`, `CO_API_KEY` | api.cohere.com, api.cohere.ai |
| Alibaba Cloud Model Studio | `DASHSCOPE_API_KEY` | dashscope-intl.aliyuncs.com, dashscope.aliyuncs.com, dashscope-us.aliyuncs.com |
| Moonshot AI | `MOONSHOT_API_KEY` | api.moonshot.ai, api.moonshot.cn |
| Z.ai | `ZAI_API_KEY` | api.z.ai, open.bigmodel.cn |
| MiniMax | `MINIMAX_API_KEY` | api.minimax.io, api.minimaxi.com |
| Hugging Face | `HF_TOKEN` | router.huggingface.co, huggingface.co |
| Cerebras | `CEREBRAS_API_KEY` | api.cerebras.ai |
| DeepInfra | `DEEPINFRA_API_KEY` | api.deepinfra.com |
| NVIDIA | `NVIDIA_API_KEY` | integrate.api.nvidia.com |

`GET /v1/secrets/presets` (`client.secrets.presets()`) lists them, with the headers each key goes in. A secret under any other name is an ordinary one, given to machines by name (see [Environment](https://docs.wheelmachine.ai/commands-and-files.html#environment)).

## Which agents use them

Each agent uses a key you have added. When there are several, each takes the first it works with, in this order: Anthropic, OpenAI, Gemini, OpenRouter, DeepSeek, xAI, Mistral AI, Groq, then the rest.

| Agent | Works with |
|---|---|
| Codex | OpenAI, OpenRouter |
| Gemini CLI | Gemini |
| Qwen Code | Anthropic, OpenAI, Gemini, OpenRouter, DeepSeek, xAI, Alibaba Cloud Model Studio |
| Aider | Anthropic, OpenAI, Gemini, OpenRouter, DeepSeek |
| Goose | Anthropic, OpenAI, Gemini, OpenRouter, DeepSeek, xAI, Mistral AI, Groq |
| Hermes Agent | Anthropic, OpenAI, Gemini, OpenRouter, DeepSeek, xAI, and more |
| OpenClaw | Anthropic, OpenAI, Gemini, OpenRouter, xAI |

Any program you run in a machine finds the keys under their names too: a provider's own library, a script, an agent you install yourself. An agent that was already running when a key was added or changed takes it when it is started again: the dashboard says so beside it, with **Restart**, and `wm apps ls` shows it as `on, restart to use new keys`.

## What never happens to the key

- It never enters a machine: not its environment, its files, its memory, or anything its programs can read. The machine holds a placeholder.
- It is sent only to its provider's hosts, over HTTPS. A request to any other host, or over plain HTTP, carries the placeholder, never the key.
- It is never shown again once it is set: not by the API, the dashboard, `wm`, the libraries, the audit or a log. It is stored encrypted.
- It never reaches another account's machines.
- Deleted, it is taken off every machine within moments.

## On every machine, as its internet lets it

An AI key is on every machine of your account: the ones made before it was added, and every one made after.

- A machine that reaches the internet (as every machine does unless it is told otherwise) gets every key.
- A machine that reaches only the places on its list gets a key when its list allows one of the key's hosts, and the key is sent only to the hosts on its list: a list is never widened for a key.
- A closed machine gets none.

A machine's `ai_keys` (`wm machines get`, and its **Secrets** part in the dashboard) says which keys reach it.

## Keep a key inside, or on some machines only

A few tools cannot work with a placeholder: one that signs each request itself, or one that does not speak HTTPS to the provider. For such a tool keep the key an ordinary secret, with `--inside`: its value is then in the environment of the machines you give it to, as any secret's is. To keep an AI key on some machines only, set it with `--only-given` and give it to each of them by name.

wm:

```sh
$ wm secrets set --only-given OPENAI_API_KEY
$ wm machines secrets box OPENAI_API_KEY
$ wm secrets set --inside GEMINI_API_KEY
```

Python:

```python
client.secrets.set("OPENAI_API_KEY", key, every_machine=False)
client.machines.update(machine.id, secrets=["OPENAI_API_KEY"])
client.secrets.set("GEMINI_API_KEY", other_key, outside=False)
```

TypeScript:

```ts
await client.secrets.set("OPENAI_API_KEY", key, { every_machine: false });
await client.machines.update(machine.id, { secrets: ["OPENAI_API_KEY"] });
await client.secrets.set("GEMINI_API_KEY", otherKey, { outside: false });
```

API:

```json
{"value": "...", "every_machine": false}
{"value": "...", "outside": false}
```

Setting a key again resets these choices: without the flags, it goes back to the default.

## Which keys work this way

An API key made in the provider's own console works. A sign-in token that renews itself, or a credential a program signs each request with (as some cloud accounts' are), does not work: keep such a one inside.

## In the API

`PUT /v1/secrets/{name}` takes `outside`: `true` adds the key on the way out (the default for an AI key's name); `false` makes it an ordinary secret; or give your own hosts, header and format for a key of any other service. `every_machine` is true by default for an AI key. See [Set a secret](https://docs.wheelmachine.ai/reference.html#setSecret) and [The AI keys the API knows](https://docs.wheelmachine.ai/reference.html#listSecretPresets).
