< Back to all hacks

#50 API Key Management (Dashboard KEYS Page)

Gateway
Problem
Changing API keys requires SSH access and manual env file editing.
Solution
Full KEYS page: view (masked), inline edit, one-tap test (hits provider API), add new keys.
Lesson
Live key testing via provider health endpoints gives instant feedback without gateway restart.

Context

PocketClaw uses multiple API keys: AI providers (Kimi, Groq, OpenAI), messaging (Telegram bot token), and optional services. Initially, changing a key required: SSH into the phone, edit ~/.openclaw/env with vi, save, restart the gateway. This multi-step process was error-prone and inaccessible to anyone who can't use a terminal.

The KEYS page provides a web interface for full API key lifecycle management, accessible from any browser on the same WiFi network.

Implementation

Each provider has a specific test endpoint:

// Test endpoints per provider type:
const testEndpoints = {
  // AI providers — GET /v1/models
  'MOONSHOT_API_KEY': 'https://api.kimi.com/coding/v1/models',
  'OPENAI_API_KEY': 'https://api.openai.com/v1/models',
  'GROQ_API_KEY': 'https://api.groq.com/openai/v1/models',

  // Telegram — GET /botXXX/getMe
  'TELEGRAM_BOT_TOKEN': (key) => `https://api.telegram.org/bot${key}/getMe`,

  // Discord — GET /users/@me
  'DISCORD_BOT_TOKEN': 'https://discord.com/api/v10/users/@me',
};

Key operations:

// GET /api/keys — list all keys (masked)
// Returns: [{ name: "MOONSHOT_API_KEY", value: "sk-...x4f2", set: true }]

// POST /api/keys — save a key
// Body: { name: "MOONSHOT_API_KEY", value: "sk-kimi-full-key-here" }
// Writes to ~/.openclaw/env AND updates process.env (no restart needed)

// POST /api/keys/test — test a key
// Body: { name: "MOONSHOT_API_KEY" }
// Hits the provider's health endpoint, returns { ok: true/false, error?: "..." }

Keys are stored in ~/.openclaw/env with mode 0600:

# ~/.openclaw/env format:
MOONSHOT_API_KEY=sk-kimi-xxx
TELEGRAM_BOT_TOKEN=8360:AAH...
GROQ_API_KEY=gsk_xxx

Verification

# Access KEYS page:
curl -s http://localhost:9000/keys | grep "MOONSHOT"
# Expected: HTML showing MOONSHOT_API_KEY (masked)

# Test a key via API:
curl -s -X POST http://localhost:9000/api/keys/test \
  -H "Content-Type: application/json" \
  -d '{"name":"MOONSHOT_API_KEY"}'
# Expected: {"ok":true} or {"ok":false,"error":"..."}

# Verify env file permissions:
ls -la ~/.openclaw/env
# Expected: -rw------- (mode 600)

Gotchas

  • Keys are masked in the GET response (showing only last 4 characters). This prevents casual shoulder-surfing on the local network
  • The POST /api/keys endpoint writes to disk AND updates process.env in the running process — no gateway restart needed
  • There's no authentication on the KEYS page. It's only accessible on the local network, but anyone on the same WiFi can access it. Consider adding basic auth for shared networks
  • Telegram bot tokens have a special format (number:hash) — the test endpoint constructs the URL differently than AI providers

Result

MetricBeforeAfter
Key change methodSSH + viWeb browser
Key testingManual curlOne-tap button
Gateway restart neededYesNo (live update)
Time to change a key2-3 min10 seconds