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: no sign-in screen, no paste box. The key itself never enters a machine.
wm
$ 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
key = client.secrets.set("ANTHROPIC_API_KEY", os.environ["MY_ANTHROPIC_KEY"])
print(key.every_machine, key.outside.hosts) # True ['api.anthropic.com']TypeScript
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
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.
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).
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
$ wm secrets set --only-given OPENAI_API_KEY
$ wm machines secrets box OPENAI_API_KEY
$ wm secrets set --inside GEMINI_API_KEYPython
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
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
{"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 and
The AI keys the API knows.
Open in Claude