Files
clawgo/docs/API.md
2026-05-10 17:27:06 +08:00

22 KiB

Gateway API

This document describes the HTTP and WebSocket API exposed by clawgo gateway run. It is based on the routes registered in pkg/api/server.go and the gateway wiring in cmd/cmd_gateway.go.

Authentication

All /api/* routes and protected extra routes require the gateway token when gateway.token is non-empty. /health does not require authentication.

Accepted token transports:

  • Authorization: Bearer <gateway.token>
  • Query parameter: ?token=<gateway.token>
  • Cookie: clawgo_webui_token=<gateway.token>
  • Browser asset fallback: a request whose Referer URL contains the same token

If gateway.token is empty, API authentication is disabled.

Unauthenticated requests return HTTP 401 with plain text:

unauthorized

Base URL

The gateway listens on gateway.host and gateway.port from config.json. The sample config uses:

http://localhost:18790

Examples below use:

BASE=http://localhost:18790
TOKEN=<gateway.token>

JSON endpoints use Content-Type: application/json unless noted otherwise.

Live Connections

The current live endpoints are WebSocket endpoints, not SSE endpoints:

  • GET /api/chat/live
  • GET /api/events/live
  • GET /api/logs/live

Connect with the same token rules as HTTP requests, for example:

ws://localhost:18790/api/events/live?token=<gateway.token>

Health Check

GET /health

Purpose: liveness probe for the gateway HTTP process.

Authentication: none.

Response:

ok

Config

GET /api/config

Purpose: read the merged gateway config. Defaults are merged with the configured config.json content.

Authentication: required when gateway.token is set.

Query parameters:

Name Description
mode=normalized Return normalized config view plus raw_config.
mode=hot Return merged config plus hot reload field metadata.
include_hot_reload_fields=1 Include hot reload field names and details.

Example:

curl -H "Authorization: Bearer $TOKEN" "$BASE/api/config?mode=normalized"

Response:

{
  "ok": true,
  "config": {},
  "raw_config": {}
}

POST /api/config

Purpose: save config and trigger gateway reload behavior.

Authentication: required.

Query parameters:

Name Description
mode=raw or omitted Body is the raw config shape.
mode=normalized Body is the normalized config view.

Example body:

{
  "gateway": {
    "host": "0.0.0.0",
    "port": 18790,
    "token": ""
  }
}

Success response:

{
  "ok": true
}

Validation errors return HTTP 400:

{
  "ok": false,
  "error": "invalid config: ...",
  "errors": ["..."]
}

Chat

POST /api/chat

Purpose: send a direct message to the Agent runtime and receive one complete reply.

Authentication: required.

Request body:

Field Required Description
session No Session key. Defaults to query session, then main.
message No Prompt text.
media No Uploaded file path. Appended to the prompt as [file: <path>].

Example:

curl -X POST "$BASE/api/chat" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"session":"main","message":"Hello"}'

Response:

{
  "ok": true,
  "reply": "Hello! How can I help?",
  "session": "main"
}

Chat History

GET /api/chat/history

Purpose: read stored messages for a session through the gateway history callback.

Authentication: required.

Query parameters:

Name Description
session Session key. Defaults to main.

Response:

{
  "ok": true,
  "session": "main",
  "messages": [
    {
      "role": "user",
      "content": "Hello"
    }
  ]
}

Live Chat

GET /api/chat/live

Purpose: WebSocket chat request that streams the completed reply in small JSON chunks.

Authentication: required.

Protocol:

  1. Client opens the WebSocket.
  2. Client sends one JSON message with session, message, and optional media.
  3. Server replies with zero or more chat_chunk messages and one chat_done message, or a chat_error message.

Client message:

{
  "session": "main",
  "message": "Summarize today",
  "media": ""
}

Server chunk:

{
  "ok": true,
  "type": "chat_chunk",
  "session": "main",
  "delta": "Partial reply text"
}

Done message:

{
  "ok": true,
  "type": "chat_done",
  "session": "main"
}

Error message:

{
  "ok": false,
  "type": "chat_error",
  "error": "invalid json",
  "session": "main"
}

Events

GET /api/events/live

Purpose: WebSocket event stream for gateway-side events such as config changes.

Authentication: required.

Initial message:

{
  "type": "ready"
}

Known event payload example:

{
  "type": "config_changed",
  "source": "webui"
}

The connection stays open until the client disconnects.

Version

GET /api/version

Purpose: read gateway build version and compiled channel keys.

Authentication: required.

Response:

{
  "ok": true,
  "gateway_version": "devel",
  "compiled_channels": ["weixin", "telegram", "feishu"]
}

Provider OAuth

Provider endpoints use the configured provider when provider is empty. Provider updates save config.json and trigger a runtime reload hook when available.

GET|POST /api/provider/oauth/start

Purpose: start a manual OAuth login flow.

Authentication: required.

GET query parameters or POST JSON fields:

Field Description
provider Provider name. Defaults to primary provider.
account_label Optional label for the imported account.
network_proxy Optional proxy override.
provider_config POST only. Inline provider config override.

Response:

{
  "ok": true,
  "flow_id": "1710000000000000000",
  "mode": "manual",
  "auth_url": "https://example.com/oauth",
  "user_code": "",
  "instructions": "Open the URL and paste the callback.",
  "account_label": "work",
  "network_proxy": ""
}

POST /api/provider/oauth/complete

Purpose: complete a previously started manual OAuth flow and persist credentials.

Authentication: required.

Request body:

{
  "provider": "codex",
  "flow_id": "1710000000000000000",
  "callback_url": "http://localhost:1455/callback?code=...",
  "account_label": "work",
  "network_proxy": ""
}

Response:

{
  "ok": true,
  "account": "user@example.com",
  "credential_file": "/home/user/.clawgo/auth/codex-work.json",
  "network_proxy": "",
  "models": ["gpt-5.4"]
}

POST /api/provider/oauth/import

Purpose: import an OAuth credential JSON file with multipart form data.

Authentication: required.

Multipart fields:

Field Required Description
file Yes Auth JSON file.
provider No Provider name.
account_label No Account label.
network_proxy No Proxy override.
provider_config No JSON encoded inline provider config.

Response:

{
  "ok": true,
  "account": "user@example.com",
  "credential_file": "/home/user/.clawgo/auth/codex-work.json",
  "network_proxy": "",
  "models": ["gpt-5.4"]
}

GET /api/provider/oauth/accounts

Purpose: list OAuth accounts for a provider.

Authentication: required.

Query parameters:

Name Description
provider Provider name. Defaults to primary provider.

Response:

{
  "ok": true,
  "accounts": []
}

POST /api/provider/oauth/accounts

Purpose: manage a provider OAuth account.

Authentication: required.

Query parameters:

Name Description
provider Provider name. Defaults to primary provider.

Request body:

{
  "action": "refresh",
  "credential_file": "/home/user/.clawgo/auth/codex-work.json"
}

Supported actions:

  • refresh
  • delete
  • clear_cooldown

Response examples:

{
  "ok": true,
  "account": {}
}
{
  "ok": true,
  "deleted": true
}
{
  "ok": true,
  "cleared": true
}

Provider Models / Runtime

POST /api/provider/models

Purpose: replace the configured model list for a provider.

Authentication: required.

Request body:

{
  "provider": "openai",
  "model": "gpt-5.4",
  "models": ["gpt-5.4", "gpt-5.4-mini"]
}

At least one value from model or models is required.

Response:

{
  "ok": true,
  "models": ["gpt-5.4", "gpt-5.4-mini"]
}

GET /api/provider/runtime

Purpose: inspect provider runtime state and history.

Authentication: required.

Query parameters:

Name Description
provider Provider name. Defaults to primary provider where applicable.
kind Runtime event kind filter.
reason Runtime reason filter.
target Runtime target filter.
sort Sort mode passed to provider runtime view.
changes_only=true Include only change events.
window_sec Time window in seconds.
limit Max result count.
cursor Cursor offset.
health_below Filter by health threshold.
cooldown_until_before_sec Filter cooldowns before now plus this many seconds.

Response:

{
  "ok": true,
  "view": {}
}

POST /api/provider/runtime

Purpose: operate on provider runtime metadata.

Authentication: required.

Request body:

{
  "provider": "codex",
  "action": "refresh_now",
  "only_expiring": true
}

Supported actions:

  • clear_api_cooldown
  • clear_history
  • refresh_now
  • rerank

Response examples:

{
  "ok": true,
  "cleared": true
}
{
  "ok": true,
  "provider": "codex",
  "refreshed": true,
  "result": {},
  "candidate_order": [],
  "summary": {}
}
{
  "ok": true,
  "provider": "codex",
  "reranked": true,
  "candidate_order": []
}

Weixin Login

GET /api/weixin/status

Purpose: read Weixin channel status, pending login records, and accounts.

Authentication: required.

Response:

{
  "ok": true,
  "enabled": false,
  "base_url": "https://ilinkai.weixin.qq.com",
  "pending_logins": [],
  "pending_login": {
    "login_id": "",
    "qr_available": false
  },
  "accounts": []
}

If the channel is unavailable, the endpoint returns HTTP 200 with ok: false and an error field.

POST /api/weixin/login/start

Purpose: start a Weixin QR login flow.

Authentication: required.

Request body: none.

Response: same shape as GET /api/weixin/status.

POST /api/weixin/login/cancel

Purpose: cancel a pending Weixin login by ID.

Authentication: required.

Request body:

{
  "login_id": "login-id"
}

Response: same shape as GET /api/weixin/status.

GET /api/weixin/qr.svg

Purpose: render the current or selected pending Weixin login QR code as SVG.

Authentication: required.

Query parameters:

Name Description
login_id Optional pending login ID. Defaults to the first pending login.

Response headers:

Content-Type: image/svg+xml

POST /api/weixin/accounts/remove

Purpose: remove a Weixin account by bot ID.

Authentication: required.

Request body:

{
  "bot_id": "bot-id"
}

Response: same shape as GET /api/weixin/status.

POST /api/weixin/accounts/default

Purpose: set the default Weixin account by bot ID.

Authentication: required.

Request body:

{
  "bot_id": "bot-id"
}

Response: same shape as GET /api/weixin/status.

Upload

POST /api/upload

Purpose: upload a file for later chat usage.

Authentication: required.

Content type: multipart/form-data.

Multipart fields:

Field Required Description
file Yes File to upload.

The server stores files under the OS temp directory in clawgo_webui_uploads.

Response:

{
  "ok": true,
  "path": "/tmp/clawgo_webui_uploads/1710000000000000000_input.txt",
  "name": "input.txt"
}

Cron

GET /api/cron

Purpose: list cron jobs or read one cron job.

Authentication: required.

Query parameters:

Name Description
id Optional job ID. When present, returns one job.

List response:

{
  "ok": true,
  "jobs": []
}

Single job response:

{
  "ok": true,
  "job": {}
}

POST /api/cron

Purpose: create or mutate cron jobs through the gateway cron handler.

Authentication: required.

Query parameters:

Name Description
id Optional job ID copied into the request args.

Request body:

{
  "action": "create",
  "name": "daily-check",
  "message": "Run daily check",
  "expr": "0 9 * * *",
  "deliver": false,
  "channel": "",
  "to": ""
}

Supported actions from the gateway runtime:

  • create
  • update
  • delete
  • enable
  • disable
  • get
  • list

Legacy scheduling fields kind, everyMs, and atMs are still accepted by the runtime for older clients.

Response:

{
  "ok": true,
  "result": {}
}

Skills

GET /api/skills

Purpose: list skills, inspect a skill's files, or read a skill file.

Authentication: required.

Query parameters:

Name Description
check_updates=1 Check ClawHub for remote versions when clawhub is installed.
id Skill ID for detail operations.
files=1 With id, list files in that skill.
file With id, read one relative text file.

List response:

{
  "ok": true,
  "skills": [],
  "source": "clawhub",
  "clawhub_installed": false,
  "clawhub_path": ""
}

Files response:

{
  "ok": true,
  "id": "example",
  "files": ["SKILL.md"]
}

File response:

{
  "ok": true,
  "id": "example",
  "file": "SKILL.md",
  "content": "# example"
}

POST /api/skills

Purpose: import, install, enable, disable, create, update, or write skill files.

Authentication: required.

Multipart upload:

  • Content-Type: multipart/form-data
  • file: .zip, .tar, .tar.gz, or .tgz archive containing one or more SKILL.md files.

Multipart response:

{
  "ok": true,
  "imported": ["my-skill"]
}

JSON body fields:

Field Description
action install, enable, disable, write_file, create, or update.
id Existing skill ID.
name Skill name. Defaults to id.
description Used by create and update.
tools String list used by create and update.
system_prompt Used by create and update.
file Relative file path for write_file.
content File content for write_file.
ignore_suspicious Adds --force to ClawHub install.

Example:

{
  "action": "disable",
  "name": "example"
}

Response:

{
  "ok": true
}

DELETE /api/skills

Purpose: delete an enabled or disabled skill directory.

Authentication: required.

Query parameters:

Name Required Description
id Yes Skill ID.

Response:

{
  "ok": true,
  "deleted": true,
  "id": "example"
}

Sessions

GET /api/sessions

Purpose: list user-facing session keys found in the main agent session store.

Authentication: required.

Query parameters:

Name Description
include_internal=1 Include internal, subagent, heartbeat, cron, and hook sessions.

Response:

{
  "ok": true,
  "sessions": [
    {
      "key": "main",
      "channel": "main"
    }
  ]
}

Memory

GET /api/memory

Purpose: list memory files or read one memory file.

Authentication: required.

Query parameters:

Name Description
path Optional relative path. MEMORY.md reads from workspace root.

List response:

{
  "ok": true,
  "files": ["MEMORY.md"]
}

File response:

{
  "ok": true,
  "path": "MEMORY.md",
  "content": "..."
}

POST /api/memory

Purpose: write a memory file under workspace/memory.

Authentication: required.

Request body:

{
  "path": "notes.md",
  "content": "Remember this."
}

Response:

{
  "ok": true,
  "path": "notes.md"
}

DELETE /api/memory

Purpose: delete a memory file under workspace/memory.

Authentication: required.

Query parameters:

Name Required Description
path Yes Relative memory file path.

Response:

{
  "ok": true,
  "deleted": true,
  "path": "notes.md"
}

Workspace File

GET /api/workspace_file

Purpose: read a relative text file under the configured workspace.

Authentication: required.

Query parameters:

Name Required Description
path Yes Relative workspace path. Absolute and .. paths are rejected.

Response:

{
  "ok": true,
  "path": "AGENTS.md",
  "found": true,
  "content": "..."
}

POST /api/workspace_file

Purpose: write a relative text file under the configured workspace. Parent directories are created when needed.

Authentication: required.

Request body:

{
  "path": "notes/today.md",
  "content": "..."
}

Response:

{
  "ok": true,
  "path": "notes/today.md",
  "saved": true
}

Tools

GET /api/tool_allowlist_groups

Purpose: read built-in tool allowlist group definitions.

Authentication: required.

Response:

{
  "ok": true,
  "groups": []
}

GET /api/tools

Purpose: read the runtime tool catalog plus MCP-specific tool and server checks.

Authentication: required.

Response:

{
  "tools": [],
  "mcp_tools": [],
  "mcp_server_checks": [
    {
      "name": "context7",
      "enabled": false,
      "transport": "stdio",
      "status": "disabled",
      "message": "server is disabled",
      "command": "npx",
      "resolved": "",
      "package": "@upstash/context7-mcp",
      "installer": "",
      "installable": false,
      "missing_command": false
    }
  ]
}

Note: this endpoint currently does not include an ok field.

MCP Install

POST /api/mcp/install

Purpose: install an MCP package through a supported package manager and resolve the installed binary path.

Authentication: required.

Request body:

{
  "package": "example-mcp",
  "installer": "uv"
}

Supported installers:

  • uv (default): runs uv tool install <package>
  • bun: runs bun add -g <package>

Response:

{
  "ok": true,
  "package": "example-mcp",
  "output": "installed example-mcp via uv",
  "bin_name": "example-mcp",
  "bin_path": "/home/user/.local/bin/example-mcp"
}

Logs

GET /api/logs/recent

Purpose: read recent log entries from the configured gateway log file.

Authentication: required.

Query parameters:

Name Description
limit Number of lines to scan. Defaults to 10, maximum 200.

Response:

{
  "ok": true,
  "logs": [
    {
      "time": "2026-05-10T00:00:00Z",
      "level": "INFO",
      "msg": "gateway started"
    }
  ]
}

JSON log lines are returned as parsed objects. Plain text lines are wrapped as time, level, and msg.

GET /api/logs/live

Purpose: WebSocket tail of new log entries from the configured gateway log file.

Authentication: required.

Server message:

{
  "ok": true,
  "type": "log_entry",
  "entry": {
    "time": "2026-05-10T00:00:00Z",
    "level": "INFO",
    "msg": "gateway started"
  }
}

If the log file cannot be opened after the WebSocket upgrade, the server sends:

{
  "ok": false,
  "error": "open ...: no such file or directory"
}

Protected Extra Routes

GET /v1/ws

Purpose: AIStudio relay WebSocket route registered by the gateway with SetProtectedRoute.

Authentication: required.

Provider selection:

  • Query parameter: provider
  • Header: X-Clawgo-Provider
  • Default: aistudio

This route is owned by pkg/wsrelay and is documented here only because the gateway registers it as a protected API-facing route.

Error Responses

Handlers mostly use Go's http.Error, so many errors are plain text with an HTTP status code instead of JSON.

Common responses:

Status Body Meaning
400 invalid json or validation text Invalid request body, missing required field, invalid path, or unsupported action.
401 unauthorized Missing or invalid gateway token.
404 ... not found Requested skill, login, QR, or resource was not found.
405 method not allowed HTTP method is not supported by that route.
412 clawhub is not installed... Skill install requires ClawHub.
429 clawhub rate limit exceeded... ClawHub rejected skill lookup or install due to rate limiting.
500 error text Gateway config, filesystem, log, cron, or runtime handler failure.
502 error text Upstream channel/login operation failed.
503 weixin channel unavailable Weixin route needs an active Weixin channel.

JSON validation responses may look like:

{
  "ok": false,
  "error": "invalid config: ...",
  "errors": ["..."]
}

WebSocket endpoints report post-upgrade errors as JSON messages when possible.

Common Flows

Send a chat message

curl -X POST "$BASE/api/chat" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"session":"main","message":"Ping"}'

Upload a file and reference it in chat

UPLOAD_PATH=$(
  curl -s -X POST "$BASE/api/upload" \
    -H "Authorization: Bearer $TOKEN" \
    -F "file=@./notes.txt" |
  jq -r .path
)

curl -X POST "$BASE/api/chat" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"session\":\"main\",\"message\":\"Read this file\",\"media\":\"$UPLOAD_PATH\"}"

Start and complete OAuth

curl -X POST "$BASE/api/provider/oauth/start" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"provider":"codex","account_label":"work"}'

Open the returned auth_url, then call:

curl -X POST "$BASE/api/provider/oauth/complete" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"provider":"codex","flow_id":"<flow_id>","callback_url":"<callback_url>"}'

Watch config and log events

Use WebSocket clients against:

ws://localhost:18790/api/events/live?token=<gateway.token>
ws://localhost:18790/api/logs/live?token=<gateway.token>