AI Assistant¶
Chat with Claude/GPT/local models, conversation history, web console deploy of OpenClaw agents, API keys, system prompts.
All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.
Endpoint count: 42
Endpoints¶
| Method | Path | Handler | Guards |
|---|---|---|---|
POST |
/api/ai/advanced/clear-sessions |
aiAdvClearSessions |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/advanced/purge-credentials |
aiAdvPurgeCredentials |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/advanced/reset-config |
aiAdvResetConfig |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/advanced/restart-gateway |
aiAdvRestartGateway |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/chat |
aiChat |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/chat-stream |
aiChatStreamV2 |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/chat/poll |
aiStatus |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/config |
getOpenClawConfig |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/config |
saveOpenClawConfig |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/crontab |
getAiCrontab |
RequirePermission(db, "administrative_operations") |
PUT |
/api/ai/crontab |
setAiCrontab |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/destroy |
destroyAiUser |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/pairing/approve |
approveAiPairing |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/reconfigure-hive |
reconfigureHive |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/restart |
restartAiService |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/setup |
setupAiAgent |
RequirePermission(db, "administrative_operations") |
GET |
/api/ai/status |
getAiStatus |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/stop |
stopAiService |
RequirePermission(db, "administrative_operations") |
GET |
/api/ai/telegram/config |
getTelegramConfig |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/telegram/config |
saveTelegramConfig |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/telegram/pairings |
getTelegramPairings |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/telegram/pairings/approve |
approveTelegramPairing |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/tui |
aiTUI |
- |
POST |
/api/ai/update-openclaw |
updateOpenClaw |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/update-openclaw/status |
getOpenClawUpdateStatus |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/vault |
listVaultSecrets |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/vault |
createVaultSecret |
RequirePermission(db, "administrative_operations") |
DELETE |
/api/ai/vault/:name |
deleteVaultSecret |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/vault/export |
exportVault |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/vault/import |
importVault |
RequirePermission(db, "administrative_operations") |
POST |
/api/ai/webconsole/disable-lan |
webConsoleDisableLAN |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/webconsole/enable-lan |
webConsoleEnableLAN |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/webconsole/fix |
webConsoleFix |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/webconsole/healthcheck |
webConsoleHealthcheck |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/webconsole/restart |
webConsoleRestart |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/webconsole/start |
webConsoleStart |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/webconsole/status |
webConsoleStatus |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/webconsole/stop |
webConsoleStop |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/whatsapp/config |
getWhatsAppConfig |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/whatsapp/config |
saveWhatsAppConfig |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/ai/whatsapp/pairings |
getWhatsAppPairings |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/ai/whatsapp/pairings/approve |
approveWhatsAppPairing |
AuthWithDB(cfg.JWTSecret, db) |
Source¶
Handlers for this section live in api/routes/handlers_*.go in the StarkOne source. Each handler binds its request body with gin.ShouldBindJSON(&req) and responds with the standard envelope:
On error:
Reference¶
POST /api/ai/advanced/clear-sessions¶
Clears all OpenClaw agent chat sessions by running openclaw sessions clear as the ai user.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Side effects
- Runs
su - ai -c 'openclaw sessions clear', deleting the agent's stored conversation sessions.
Example
curl -X POST https://panel.example.com:2087/api/ai/advanced/clear-sessions \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/advanced/purge-credentials¶
Removes all stored AI credentials: clears the credentials directory, empties the vault, deletes .env files, strips API keys/tokens from openclaw.json, and restarts the gateway.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
{ "data": { "output": "✅ Cleared credentials/\n✅ Stripped API keys from openclaw.json\n🔄 Gateway restarted\n⚠️ All credentials removed. Reconfigure providers in Config tab." } }
Side effects
rm -rf /home/ai/.openclaw/credentials/*.- Overwrites
/home/ai/.openclaw/vault/secrets.jsonwith{"secrets":[]}. - Removes
.env/*.envfiles under/home/ai/.openclaw. - Strips
apiKey/token/keyfrom auth profiles and channel tokens inopenclaw.jsonvia an inlinepython3script. - Restarts the OpenClaw gateway (
su - ai -c 'openclaw gateway restart').
Example
curl -X POST https://panel.example.com:2087/api/ai/advanced/purge-credentials \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/advanced/reset-config¶
Resets openclaw.json to defaults (preserving the auth section), backing up the existing config first, then restarts the gateway.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
{ "data": { "output": "✅ Configuration reset to defaults (credentials preserved)\n🔄 Gateway restarted" } }
Side effects
- Backs up
/home/ai/.openclaw/openclaw.jsontoopenclaw.json.bak.<epoch>. - Rewrites
openclaw.jsonkeeping onlyauth, plus defaultagentsand emptychannels(default modelanthropic/claude-sonnet-4-6, workspace/home/ai/.openclaw/workspace). chown ai:aithe config and restarts the gateway.
Example
curl -X POST https://panel.example.com:2087/api/ai/advanced/reset-config \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/advanced/restart-gateway¶
Restarts the OpenClaw gateway and returns its status output.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Side effects
- Runs
su - ai -c 'openclaw gateway restart'followed byopenclaw gateway status.
Example
curl -X POST https://panel.example.com:2087/api/ai/advanced/restart-gateway \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/chat¶
Sends a single message to the OpenClaw agent over its local HTTP API and returns the agent's reply (non-streaming).
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
message |
string | yes | The user message to send to the agent. |
sessionKey |
string | no | Session identifier; defaults to agent:main:main. |
Response - 200 OK
If no reply is produced, reply is the literal string (no reply).
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed binding (e.g. missing message). |
503 |
ai_not_configured |
Gateway token not found in openclaw.json; AI agent not set up. |
503 |
gateway_error |
HTTP request to the local OpenClaw gateway failed. |
Example
curl -X POST https://panel.example.com:2087/api/ai/chat \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "Restart nginx", "sessionKey": "agent:main:main"}'
POST /api/ai/chat-stream¶
Streams the OpenClaw agent's response token-by-token over Server-Sent Events by relaying a WebSocket session with the local gateway.
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
message |
string | yes | The user message to send to the agent. |
sessionKey |
string | no | Session identifier; defaults to agent:main:main. |
Response - 200 OK
Content-Type: text/event-stream. Each SSE data: line carries a JSON object: an initial {"type":"start"}, then {"type":"chunk","content":"..."} deltas, ending with {"type":"done","content":"<full text>"}.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
message is required. |
503 |
ai_not_configured |
Gateway token not found; AI agent not set up. |
503 |
gateway_unavailable |
Could not open WebSocket to the gateway. |
503 |
challenge_failed |
Failed reading the gateway challenge frame. |
503 |
auth_failed |
Failed reading the gateway hello/auth response. |
503 |
auth_rejected |
Gateway rejected the connection. |
Example
curl -X POST https://panel.example.com:2087/api/ai/chat-stream \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "Tail the error log"}'
GET /api/ai/chat/poll¶
Polls the latest assistant reply from the agent:main:main session history (used for polling-based chat UIs).
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
status is not_configured when no gateway token is found, or error (with an error field) when the gateway request fails. This handler always responds 200.
Example
GET /api/ai/config¶
Returns the parsed openclaw.json config plus per-provider API keys read from the credentials directory.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
{ "data": { "config": { "gateway": {}, "agents": {} }, "credentials": { "anthropic": "sk-...", "custom_base_url": "https://..." } } }
credentials includes any of anthropic, openai, google, deepseek, groq, custom whose default.key file exists, plus custom_base_url if set.
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
read_failed |
Could not read /home/ai/.openclaw/openclaw.json. |
500 |
parse_failed |
Config file is not valid JSON. |
Example
POST /api/ai/config¶
Saves the OpenClaw config and writes provider credentials to credential files, an .env file, an auth-profiles file, and (for a custom gateway) a systemd environment override.
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
{ "config": { "gateway": {} }, "credentials": { "anthropic": "sk-...", "custom_base_url": "https://api.example.com" } }
| Field | Type | Required | Description |
|---|---|---|---|
config |
object | no | Full OpenClaw config object written to openclaw.json. |
credentials |
object (string→string) | no | Map of provider name to API key; custom_base_url sets the custom gateway base URL. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
invalid_json |
Request body could not be bound. |
500 |
marshal_failed |
Config could not be serialized. |
500 |
write_failed |
Could not write openclaw.json. |
Side effects
- Saves a version-history snapshot of
.openclaw/openclaw.json, then overwrites it (chown ai:ai). - Writes each provider key to
/home/ai/.openclaw/credentials/<provider>/default.keyand the custom base URL tocredentials/custom/base_url. - Writes
/home/ai/.openclaw/.envwith<PROVIDER>_API_KEYlines (custom →OPENAI_API_KEY/OPENAI_BASE_URL). - Writes
/home/ai/.openclaw/agents/main/agent/auth-profiles.json. - For a custom gateway, writes a systemd override at
/etc/systemd/system/<svc>.service.d/gateway.confand runssystemctl daemon-reload; otherwise removes that override and the custom credential files and reloads the daemon.
Example
curl -X POST https://panel.example.com:2087/api/ai/config \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"config": {"gateway": {"mode": "local"}}, "credentials": {"anthropic": "sk-ant-..."}}'
GET /api/ai/crontab¶
Returns the ai user's crontab entries parsed into schedule/command pairs.
Guards: RequirePermission(db, "administrative_operations")
Response - 200 OK
The data array is empty/null when the crontab has no entries. Lines starting with @ (e.g. @daily) are parsed as a single-token schedule.
Example
PUT /api/ai/crontab¶
Replaces the ai user's crontab with the supplied jobs.
Guards: RequirePermission(db, "administrative_operations")
Request body
| Field | Type | Required | Description |
|---|---|---|---|
jobs |
array of {schedule, command} |
yes | Cron entries to install. Entries with an empty schedule or command are skipped. |
Response - 200 OK
This handler returns a flat (non-enveloped) body.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed binding. |
500 |
(none) | Failed to update crontab when crontab -u ai - fails. |
Side effects
- Pipes the rendered crontab to
crontab -u ai -, overwriting theaiuser's crontab.
Example
curl -X PUT https://panel.example.com:2087/api/ai/crontab \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"jobs": [{"schedule": "0 3 * * *", "command": "openclaw run nightly"}]}'
POST /api/ai/destroy¶
Completely removes the AI user: stops/disables its services, kills its processes, deletes its home directory and system account, and purges its panel DB records.
Guards: RequirePermission(db, "administrative_operations")
Request body
| Field | Type | Required | Description |
|---|---|---|---|
confirm |
string | yes | Must equal DESTROY exactly, or the request is rejected. |
Response - 200 OK
{ "data": { "status": "success", "steps": ["Stopped and disabled all AI services", "Removed /home/ai directory"], "errors": [], "message": "AI user destroyed. Re-enable from the AI tab if needed." } }
status is partial when any step recorded an error (errors are listed in errors).
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
confirmation_required |
Body missing or confirm is not DESTROY. |
Side effects
systemctl stop/disableand removes service files foropenclaw,openclaw-ai,ai-agent; runssystemctl daemon-reload.pkill -u ai/killall -u ai.os.RemoveAll("/home/ai")(vault, config, workspace).userdel ai.- Deletes the
airow fromusersand itsapi_keysrows. - Removes
aientries from/etc/csf/csf.pignoreviased.
Example
curl -X POST https://panel.example.com:2087/api/ai/destroy \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"confirm": "DESTROY"}'
POST /api/ai/pairing/approve¶
Approves a pending Telegram device pairing by code via the OpenClaw CLI.
Guards: RequirePermission(db, "administrative_operations")
Request body
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | yes | Pairing code; trimmed and upper-cased before use. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed binding (missing code). |
500 |
pairing_failed |
The openclaw pairing approve telegram command failed (message contains its output). |
Side effects
- Runs
su - ai -c 'openclaw pairing approve telegram <code>'.
Example
curl -X POST https://panel.example.com:2087/api/ai/pairing/approve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "ABC123"}'
POST /api/ai/reconfigure-hive¶
Reconfigures the gateway for "hive" mode: token auth, LAN bind, Telegram disabled, device auth bypassed, and a chosen default model.
Guards: RequirePermission(db, "administrative_operations")
Request body
| Field | Type | Required | Description |
|---|---|---|---|
model |
string | yes | Primary model id set as agents.defaults.model.primary. |
Response - 200 OK
{ "status": "ok", "message": "Hive mode configured", "token": "<48-char hex>", "model": "anthropic/claude-sonnet-4-20250514" }
Flat (non-enveloped) body. A freshly generated gateway token is returned.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
model is required. |
500 |
token_gen_failed |
Random token generation failed. |
500 |
(none) | status: "partial" with errors array when one or more openclaw config set commands fail. |
Side effects
- Runs a series of
su - ai -c 'timeout 15 openclaw config set <key> <value>'commands settinggateway.auth.mode=token,gateway.auth.token=<new>,gateway.bind=lan,channels.telegram.enabled=false,gateway.controlUi.dangerouslyDisableDeviceAuth=true, andagents.defaults.model.primary=<model>.
Example
curl -X POST https://panel.example.com:2087/api/ai/reconfigure-hive \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"model": "anthropic/claude-sonnet-4-20250514"}'
POST /api/ai/restart¶
Restarts the active OpenClaw systemd service.
Guards: RequirePermission(db, "administrative_operations")
Response - 200 OK
Flat (non-enveloped) body. The service name is auto-detected (openclaw-ai or openclaw).
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
restart_failed |
systemctl restart <svc> failed. |
Side effects
- Runs
systemctl restart <openclaw service>.
Example
POST /api/ai/setup¶
Provisions the AI agent: creates the ai OS/panel user if needed, issues an API key, and runs the CLI setup_ai_agent with the chosen provider and credentials.
Guards: RequirePermission(db, "administrative_operations")
Request body
{ "provider": "anthropic", "apiKey": "sk-...", "telegramToken": "123:ABC", "telegramOwnerId": "12345678" }
| Field | Type | Required | Description |
|---|---|---|---|
provider |
string | yes | One of anthropic, openai, google. |
apiKey |
string | yes | Provider API key. |
telegramToken |
string | yes | Telegram bot token. |
telegramOwnerId |
string | no | Telegram owner/user id. |
Response - 200 OK
Flat (non-enveloped) body.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed binding, or provider not in the allowed set. |
500 |
db_error |
Failed creating the ai user record or reading its id, or inserting the API key. |
500 |
server_error |
Failed to generate the API key. |
500 |
setup_failed |
The CLI setup_ai_agent command failed. |
Side effects
- On first setup: creates OS user
ai(random password viauseradd_starkone), ensures/home/aiand.sshexist with correct ownership, inserts an admin/superuserairow inusers, writes/etc/sudoers.d/ai-nopasswd, and addsaitosudo/wheel. - Deletes any existing
ai-agentAPI key, then inserts a new hashedbap_...key for theaiuser. - Runs CLI
setup_ai_agent <provider> <apiKey> <telegramToken> <token> <telegramOwnerId>.
Example
curl -X POST https://panel.example.com:2087/api/ai/setup \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"provider": "anthropic", "apiKey": "sk-ant-...", "telegramToken": "123:ABC", "telegramOwnerId": "12345678"}'
GET /api/ai/status¶
Reports whether OpenClaw is installed, configured, and running, plus memory and uptime.
Guards: RequirePermission(db, "administrative_operations")
Response - 200 OK
{ "data": { "installed": true, "configured": true, "running": true, "memory_mb": 128.5, "uptime_minutes": 42 } }
Side effects
- Read-only inspection:
os.Statof config/binary,pgrep -u ai,ps -u ai, andsystemctl show openclaw. (No state change.)
Example
POST /api/ai/stop¶
Stops the OpenClaw service, optionally force-killing all related processes.
Guards: RequirePermission(db, "administrative_operations")
Request body
| Field | Type | Required | Description |
|---|---|---|---|
force |
boolean | no | When true, force-kill all openclaw processes before stopping the service. |
Response - 200 OK
Flat (non-enveloped) body; message is AI service force-killed when force is true.
Side effects
- When
force:killall -9 openclaw-gateway,killall -9 openclaw,pkill -9 -u ai -f openclaw. - Always:
systemctl stop <openclaw service>.
Example
curl -X POST https://panel.example.com:2087/api/ai/stop \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"force": true}'
GET /api/ai/telegram/config¶
Returns the Telegram channel config extracted from openclaw.json.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
{ "data": { "botToken": "123:ABC", "dmPolicy": "allowlist", "groupPolicy": "allowlist", "allowFrom": ["12345678"], "requireMention": true, "groups": ["-100123"] } }
Returns { "data": {} } when the config file is missing or unparseable. requireMention is read from the * group entry (default true); groups lists non-* group ids.
Example
POST /api/ai/telegram/config¶
Writes the Telegram channel config into openclaw.json.
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
{ "botToken": "123:ABC", "dmPolicy": "allowlist", "groupPolicy": "allowlist", "allowFrom": ["12345678"], "groups": ["-100123"], "requireMention": true }
| Field | Type | Required | Description |
|---|---|---|---|
botToken |
string | no | Telegram bot token. |
dmPolicy |
string | no | Direct-message policy. |
groupPolicy |
string | no | Group-message policy. |
allowFrom |
array of string | no | Allowed sender ids. |
groups |
array of string | no | Specific group ids to add (besides the * default). |
requireMention |
boolean | no | Whether the bot must be mentioned in groups (stored under the * group). |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
(none) | Body failed binding (error.message only). |
500 |
(none) | Failed writing openclaw.json (error.message only). |
Side effects
- Merges a
channels.telegramobject intoopenclaw.json, writes the file, andchown ai:ai.
Example
curl -X POST https://panel.example.com:2087/api/ai/telegram/config \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"botToken": "123:ABC", "requireMention": true, "allowFrom": ["12345678"]}'
GET /api/ai/telegram/pairings¶
Lists pending/known Telegram pairings via the OpenClaw CLI.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
pairings is the JSON array returned by openclaw pairing list telegram --json (empty array on error).
Example
POST /api/ai/telegram/pairings/approve¶
Approves a Telegram pairing by code via the OpenClaw CLI.
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | no | Pairing code (passed directly to the CLI; no binding constraint). |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
(none) | Body failed binding (error.message only). |
500 |
(none) | Failed to approve pairing when the CLI command fails. |
Side effects
- Runs
su - ai -c 'openclaw pairing approve telegram <code>'.
Example
curl -X POST https://panel.example.com:2087/api/ai/telegram/pairings/approve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "ABC123"}'
GET /api/ai/tui¶
Upgrades the connection to a WebSocket terminal running the OpenClaw TUI as the ai user. Authentication is via a JWT in the token query param (not the bearer header).
Guards: - (no router guard; authenticated inline via the token query param, which must be a valid JWT with superuser: true)
Query parameters
| Name | Type | Optional | Description |
|---|---|---|---|
token |
string | no | JWT carrying superuser claims; required to authorize the WebSocket upgrade. |
Response - 200 OK
Not a JSON body - the connection is upgraded to a WebSocket streaming an interactive openclaw tui --session main terminal.
Errors
| Status | Code | Meaning |
|---|---|---|
401 |
unauthorized |
Missing token query param. |
403 |
forbidden |
Token invalid or not a superuser. |
Side effects
- Reads the gateway token from
openclaw.json, auto-approves any pending OpenClaw devices, and spawns an interactiveopenclaw tuiprocess for theaiuser over the socket.
Example
POST /api/ai/update-openclaw¶
Streams the OpenClaw npm update process (and gateway restart) over Server-Sent Events.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Content-Type: text/event-stream. Emits progress lines as data: events (e.g. update output, restart messages, final version), terminating with a [DONE] event.
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
(none) | streaming not supported if the writer does not support flushing. |
Side effects
- Runs
npm update -g openclaw, thensu - ai -c 'openclaw gateway restart', thenopenclaw --version.
Example
curl -X POST https://panel.example.com:2087/api/ai/update-openclaw \
-H "Authorization: Bearer $TOKEN"
GET /api/ai/update-openclaw/status¶
Reports the installed OpenClaw version, the latest npm version, and whether an update is available.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Side effects
- Read-only: runs
openclaw --versionandnpm view openclaw version.
Example
curl https://panel.example.com:2087/api/ai/update-openclaw/status \
-H "Authorization: Bearer $TOKEN"
GET /api/ai/vault¶
Lists vault secret metadata (names/types, no values) via the vault skill script.
Guards: RequirePermission(db, "administrative_operations")
Response - 200 OK
Returns { "data": { "secrets": [] } } if the script output is not valid JSON.
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
vault_error |
The vault.sh list command failed. |
Side effects
- Runs
su - ai -c 'bash /home/ai/.openclaw/skills/vault/vault.sh list'(read-only).
Example
POST /api/ai/vault¶
Creates or updates a vault secret via the vault skill script.
Guards: RequirePermission(db, "administrative_operations")
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Secret name. |
type |
string | yes | One of api_key, password, ssh_key, token, json_array, secret. |
value |
string | yes | Secret value. |
description |
string | no | Human-readable description. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed binding, or type not in the allowed set. |
500 |
vault_error |
The vault.sh set command failed (message contains its output). |
Side effects
- Runs
su - ai -c 'bash vault.sh set <name> <type> <value> <description>', writing the secret into the vault.
Example
curl -X POST https://panel.example.com:2087/api/ai/vault \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "stripe_key", "type": "api_key", "value": "sk-...", "description": "Stripe live key"}'
DELETE /api/ai/vault/:name¶
Deletes a vault secret by name via the vault skill script.
Guards: RequirePermission(db, "administrative_operations")
Path parameters
| Name | Type | Description |
|---|---|---|
name |
string | Name of the secret to delete. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Secret name missing. |
500 |
vault_error |
The vault.sh delete command failed. |
Side effects
- Runs
su - ai -c 'bash vault.sh delete <name>'.
Example
curl -X DELETE https://panel.example.com:2087/api/ai/vault/stripe_key \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/vault/export¶
Exports all vault secrets as an encrypted tar.gz download (always encrypted with an internal key, plus the user password if supplied).
Guards: RequirePermission(db, "administrative_operations")
Request body
| Field | Type | Required | Description |
|---|---|---|---|
password |
string | no | Extra passphrase; when present, the archive is encrypted a second time with it. |
Response - 200 OK
Streams a file (Content-Type: application/octet-stream, Content-Disposition: attachment; filename=vault-export.tar.gz.enc) - not a JSON envelope.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
empty_vault |
No secrets to export. |
500 |
temp_error |
Could not create temp dir. |
500 |
vault_error |
Failed listing secrets. |
500 |
parse_error |
Failed parsing the secret list. |
500 |
tar_error |
tar failed. |
500 |
encrypt_error |
openssl encryption failed. |
Side effects
- Writes secret values/metadata to a temp dir, tars them, and runs
openssl enc -aes-256-cbc(once with the internal key, again with the user password if given). Temp dir is removed afterward.
Example
curl -X POST https://panel.example.com:2087/api/ai/vault/export \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"password": "passphrase"}' \
-o vault-export.tar.gz.enc
POST /api/ai/vault/import¶
Imports secrets from an uploaded encrypted vault archive (multipart form), decrypting and restoring each secret.
Guards: RequirePermission(db, "administrative_operations")
Request body
Multipart form, not JSON:
| Field | Type | Required | Description |
|---|---|---|---|
file |
file | yes | The exported .tar.gz.enc archive. |
password |
form field | no | User passphrase used during export (if any). |
overwrite |
form field | no | 1 to overwrite existing secrets; otherwise duplicates are skipped. |
Response - 200 OK
Flat (non-enveloped) body.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Missing file. |
400 |
decrypt_error |
Invalid password for the user-encryption layer. |
400 |
extract_error |
Archive could not be extracted (invalid archive). |
500 |
temp_error |
Could not create temp dir. |
500 |
file_error |
Could not save the uploaded file. |
Side effects
- Decrypts with
openssl(user layer then internal layer), extracts the archive, and runssu - ai -c 'bash vault.sh set ...'for each restored secret.
Example
curl -X POST https://panel.example.com:2087/api/ai/vault/import \
-H "Authorization: Bearer $TOKEN" \
-F "[email protected]" \
-F "password=passphrase" \
-F "overwrite=1"
POST /api/ai/webconsole/disable-lan¶
Disables LAN access for the OpenClaw web console: reverts the gateway to loopback, removes the nginx proxy, and restarts the gateway.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
read_failed |
Could not read openclaw.json. |
500 |
parse_failed |
Config is not valid JSON. |
500 |
write_failed |
Could not write openclaw.json. |
Side effects
- Deletes
gateway.bindandgateway.controlUifromopenclaw.json, writes it,chown ai:ai. - Removes
/etc/nginx/conf.d/openclaw-proxy.confand reloads nginx. - Restarts the gateway (
pkill -u ai openclawthen relaunch).
Example
curl -X POST https://panel.example.com:2087/api/ai/webconsole/disable-lan \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/webconsole/enable-lan¶
Enables LAN access for the web console: binds the gateway to LAN, relaxes control-UI origin/device-auth, installs an HTTPS nginx proxy on port 18790, and restarts the gateway.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
read_failed |
Could not read openclaw.json. |
500 |
parse_failed |
Config is not valid JSON. |
500 |
write_failed |
Could not write openclaw.json. |
Side effects
- Sets
gateway.bind=lanandgateway.controlUi(allowed origins*,dangerouslyDisableDeviceAuth: true) inopenclaw.json, writes it,chown ai:ai. - Writes
/etc/nginx/conf.d/openclaw-proxy.conf(TLS proxy on 18790 → 127.0.0.1:18789), runsnginx -t, reloads nginx. - Restarts the gateway.
Example
curl -X POST https://panel.example.com:2087/api/ai/webconsole/enable-lan \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/webconsole/fix¶
Auto-fixes the most common console misconfiguration by setting gateway.mode=local in openclaw.json.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
read_failed |
Could not read openclaw.json. |
500 |
parse_failed |
Config is not valid JSON. |
500 |
marshal_failed |
Could not serialize the updated config. |
500 |
write_failed |
Could not write openclaw.json. |
Side effects
- Sets
gateway.mode=localinopenclaw.json, writes it, andchown ai:ai.
Example
curl -X POST https://panel.example.com:2087/api/ai/webconsole/fix \
-H "Authorization: Bearer $TOKEN"
GET /api/ai/webconsole/healthcheck¶
Runs a full diagnostic of the OpenClaw web console (install, config, gateway mode/bind, process, port, firewall) and lists any issues.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
{ "data": { "openclaw_installed": true, "config_exists": true, "gateway_mode": "local", "gateway_mode_ok": true, "gateway_bind": "lan", "gateway_bind_lan": true, "gateway_token": "<token>", "process_running": true, "port_responding": true, "all_ok": true, "issues": [], "can_auto_fix": false, "client_ip": "203.0.113.10", "firewall_18790_open": true } }
Side effects
- Read-only checks:
LookPath openclaw, readsopenclaw.json,pgrep -u ai openclaw, HTTP GET to127.0.0.1:18789, andfirewall-cmd/iptablesfor port 18790.
Example
curl https://panel.example.com:2087/api/ai/webconsole/healthcheck \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/webconsole/restart¶
Restarts the OpenClaw gateway process for the ai user and verifies it came back up.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
restart_failed |
Failed to launch the gateway. |
500 |
not_started |
Process did not start (no matching pgrep after relaunch). |
Side effects
pkill -u ai openclaw, thensu - ai -c 'nohup openclaw gateway run ...', then verifies viapgrep.
Example
curl -X POST https://panel.example.com:2087/api/ai/webconsole/restart \
-H "Authorization: Bearer $TOKEN"
POST /api/ai/webconsole/start¶
Starts a web-console proxy session for the caller's IP, returning a per-IP session token.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Side effects
- Stores a random session token keyed by the client IP in an in-memory map (no disk/service change).
Example
curl -X POST https://panel.example.com:2087/api/ai/webconsole/start \
-H "Authorization: Bearer $TOKEN"
GET /api/ai/webconsole/status¶
Returns whether the caller's IP has an active web-console session and its token.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Example
POST /api/ai/webconsole/stop¶
Ends the web-console session for the caller's IP.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Side effects
- Removes the in-memory session entry for the client IP.
Example
curl -X POST https://panel.example.com:2087/api/ai/webconsole/stop \
-H "Authorization: Bearer $TOKEN"
GET /api/ai/whatsapp/config¶
Returns the WhatsApp channel config from openclaw.json plus the live connection status from the OpenClaw CLI.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
{ "data": { "status": "connected", "phone": "+1555...", "dmPolicy": "allowlist", "groupPolicy": "allowlist", "allowFrom": ["+1555..."], "groupAllowFrom": [], "allowedGroups": [], "requireMention": true } }
Returns { "data": { "status": "disconnected" } } when the config file is missing or unparseable. status/phone come from openclaw channels status whatsapp --json.
Example
POST /api/ai/whatsapp/config¶
Writes the WhatsApp channel config into openclaw.json.
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
{ "dmPolicy": "allowlist", "groupPolicy": "allowlist", "allowFrom": ["+1555..."], "groupAllowFrom": [], "allowedGroups": [], "requireMention": true }
| Field | Type | Required | Description |
|---|---|---|---|
dmPolicy |
string | no | Direct-message policy. |
groupPolicy |
string | no | Group-message policy. |
allowFrom |
array of string | no | Allowed DM sender numbers. |
groupAllowFrom |
array of string | no | Allowed group sender numbers. |
allowedGroups |
array of string | no | Allowed group ids. |
requireMention |
boolean | no | Whether the bot must be mentioned in groups (stored under the * group). |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
(none) | Body failed binding (error.message only). |
500 |
(none) | Failed writing openclaw.json (error.message only). |
Side effects
- Merges a
channels.whatsappobject intoopenclaw.json, writes the file, andchown ai:ai.
Example
curl -X POST https://panel.example.com:2087/api/ai/whatsapp/config \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"dmPolicy": "allowlist", "allowFrom": ["+15551234567"], "requireMention": true}'
GET /api/ai/whatsapp/pairings¶
Lists WhatsApp pairings via the OpenClaw CLI.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
pairings is the JSON array from openclaw pairing list whatsapp --json (empty array on error).
Example
POST /api/ai/whatsapp/pairings/approve¶
Approves a WhatsApp pairing by code via the OpenClaw CLI.
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | no | Pairing code (passed directly to the CLI; no binding constraint). |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
(none) | Body failed binding (error.message only). |
500 |
(none) | Failed to approve pairing when the CLI command fails. |
Side effects
- Runs
su - ai -c 'openclaw pairing approve whatsapp <code>'.
Example