Secrets API
Read and write env vars for the active agent.
The secrets API is a thin layer over the active agent's .env file (typically ~/.openclaw/.env). It powers the Settings → Env Vars UI and onboarding "do you have an ANTHROPIC_API_KEY?" checks.
GET /api/secrets/env returns plaintext values, including secrets. Only the workspace itself should expose this surface; never tunnel it past the trust boundary without an auth layer.
Endpoint summary
| Verb | Path | Purpose |
|---|---|---|
GET | /api/secrets/env | List all entries with values. Plaintext on the wire. |
GET | /api/secrets/env/keys | Names only (non-empty values). No secret material on the wire. |
PUT | /api/secrets/env | Replace the entire env file with the given entries. |
1. GET /api/secrets/env
Response (200 OK)
{
"entries": [
{ "key": "ANTHROPIC_API_KEY", "value": "sk-ant-..." },
{ "key": "OPENAI_API_KEY", "value": "sk-proj-..." },
{ "key": "GITHUB_TOKEN", "value": "ghp_..." }
]
}The reader (load_env_entries) parses ~/.openclaw/.env:
- Skips blank lines and lines starting with
#. - Splits on the first
=. Strips both sides. - Returns a list of
{key, value}pairs in file order.
2. GET /api/secrets/env/keys
Use this on onboarding flows when you need to detect whether a key is set without exposing its value.
Response (200 OK)
{
"keys": ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GITHUB_TOKEN"]
}Only keys with non-empty values are listed. Blank-valued keys (KEY=) are filtered out.
3. PUT /api/secrets/env
Overwrite the entire .env file.
Request
{
"entries": [
{ "key": "ANTHROPIC_API_KEY", "value": "sk-ant-new..." },
{ "key": "OPENAI_API_KEY", "value": "sk-proj-..." }
]
}Behavior
1. Truncate the .env file.
2. For each entry with non-empty `key`:
write `{key}={value}\n`
3. Entries with empty `key` are skipped silently.This is a full overwrite. Comments, blank lines, and any keys not in the request body are lost. There is no merge mode here.
If you want to update a single key without losing comments or unrelated keys, use the onboarding "Save Key" flow inside routers/cowork_agent/config.py, which goes through upsert_env_entry() (line-level edit). That path is not part of /api/secrets/*.
Response (200 OK)
{ "ok": true }Frontend pattern
A typical settings UI:
// Load
const { entries } = await fetch(`${BASE}/api/secrets/env`).then(r => r.json());
setForm(entries);
// Save (after user edits)
await fetch(`${BASE}/api/secrets/env`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ entries: form }),
});For a "is this connected?" indicator without exposing the value:
const { keys } = await fetch(`${BASE}/api/secrets/env/keys`).then(r => r.json());
const hasAnthropic = keys.includes("ANTHROPIC_API_KEY");Security notes
- The
.envfile lives at~/.openclaw/.env(or whichever path the active agent's manifest declares). - The cowork-api process reads and writes it directly. There is no DB, no encryption-at-rest, no per-user scoping.
- Workspace = trust boundary. Anyone who can reach the API endpoint can read every secret.