10 KiB
Gateway API Research
Generated: 2026-06-10 Auth mode: password (not token)
1. Authentication
Auth mode: password
Credential: ieDm...PAg (masked: ieDmOiBiVfbbDM0ibrEebPAg → use ieDm...PAg)
How to authenticate
Authorization: Bearer <password>
All requests to POST /tools/invoke must include the Authorization: Bearer header with the gateway password from gateway.auth.password.
Configuration (from openclaw.json)
{
gateway: {
mode: "local",
port: 18789,
bind: "loopback", // Only reachable from localhost
auth: {
mode: "password",
password: "ieDmOjBiVfbbDM0ibrEebPAg",
rateLimit: {
maxAttempts: 10,
windowMs: 60000,
lockoutMs: 300000,
exemptLoopback: true
}
},
controlUi: {
allowInsecureAuth: true,
allowedOrigins: ["https://openclaw.noveria.net"]
},
tools: {
// Default deny list applies (see below)
}
}
}
Notes
- Loopback only:
gateway.bind: "loopback"means the API only listens on127.0.0.1:18789. - Rate limiting: 10 failed attempts per 60s window → 5min lockout. Loopback is exempt.
- Control UI: Allowed origin:
https://openclaw.noveria.net
2. API Endpoint: POST /tools/invoke
URL: http://127.0.0.1:18789/tools/invoke
Method: POST
Content-Type: application/json
Auth: Authorization: Bearer <password>
Max payload size: 2 MB
Request body structure
{
"tool": "<tool_name>",
"action": "<optional_action>",
"args": { },
"sessionKey": "main",
"dryRun": false
}
Responses
| Code | Meaning |
|---|---|
| 200 | Success: { ok: true, result: ... } |
| 400 | Invalid request/tool input: { ok: false, error: { type, message } } |
| 401 | Unauthorized |
| 404 | Tool not found or not allowlisted |
| 405 | Method not allowed |
| 429 | Rate limited (with Retry-After header) |
| 500 | Tool execution error: { ok: false, error: { type, message } } |
Default HTTP Deny List (cannot be invoked via HTTP)
These tools are blocked by default on the HTTP endpoint (policy):
| Tool | Reason |
|---|---|
exec |
RCE surface |
spawn |
RCE surface |
shell |
RCE surface |
fs_write |
Arbitrary file mutation |
fs_delete |
Arbitrary file deletion |
fs_move |
Arbitrary file move/rename |
apply_patch |
Can rewrite files |
sessions_spawn |
Session orchestration / remote agent spawning |
sessions_send |
Cross-session message injection |
cron |
Persistent automation control plane |
gateway |
Gateway control plane (prevents reconfiguration via HTTP) |
nodes |
Node command relay |
whatsapp_login |
Interactive setup; hangs on HTTP |
Override example (add to gateway.tools in config):
{
gateway: {
tools: {
deny: ["browser"], // extra blocks
allow: ["gateway"], // remove from default deny
}
}
}
3. Tested Tools & Responses
Note: Direct HTTP testing was not possible from this session (exec sandbox unavailable). Documentation based on API spec and config analysis.
3.1 session_status
Request:
{ "tool": "session_status", "args": {} }
Expected response structure:
{
"ok": true,
"result": {
"sessionKey": "main",
"agentId": "iris",
"modelId": "openai/gpt-5.4",
"channel": "webchat",
"created": "<ISO timestamp>",
"active": true,
"toolsAvailable": ["read", "write", "edit", "exec", ...],
"subagentDepth": 1,
"runtimeInfo": { "thinking": "high", "modelIdentity": "deepseek/deepseek-v4-flash" }
}
}
3.2 sessions_list
Request:
{ "tool": "sessions_list", "args": { "kinds": ["main", "subagent"] } }
Expected response:
Array of active sessions with keys like iris-main, programmer-subagent-xxx, etc.
3.3 subagents
Request:
{ "tool": "subagents", "args": { "action": "list" } }
Expected response: List of configured subagents for the active session.
3.4 sessions_history
Request:
{ "tool": "sessions_history", "args": { "sessionKey": "iris-main", "limit": 10 } }
Expected response: Array of recent messages/events from the specified session. Fields include:
role(user/assistant/tool)content(message text)timestamptool_calls(if applicable)
3.5 memory_search
Request:
{ "tool": "memory_search", "args": { "query": "...", "maxResults": 5 } }
Expected response:
{
"ok": true,
"result": [
{
"content": "...",
"path": "memory/YYYY-MM-DD.md",
"score": 0.95,
"metadata": { "...": "..." }
}
]
}
3.6 Health Check (non-tools/invoke)
Request:
GET http://127.0.0.1:18789/health
Expected response: "OK" or { "status": "ok" }
4. Data Structures for Dashboard Integration
Tool Call Response - Success
{
"ok": true,
"result": <any>
}
Tool Call Response - Error
{
"ok": false,
"error": {
"type": "string",
"message": "string"
}
}
Session Object (from sessions_list / session_status)
| Field | Type | Description |
|---|---|---|
| sessionKey | string | Unique session identifier |
| agentId | string | Agent id (e.g., "iris", "programmer") |
| modelId | string | Model in use |
| channel | string | Channel type (webchat, slack, etc.) |
| created | ISO timestamp | Session creation time |
| active | boolean | Whether session is processing |
| subagentDepth | number | Current subagent nesting level |
Session History Entry
| Field | Type | Description |
|---|---|---|
| role | string | "user", "assistant", "tool", "system" |
| content | string | Message content |
| timestamp | ISO string | When the message was sent |
| tool_calls | array[] | Tool invocation details (if assistant) |
| tool_call_id | string | Matches tool response to request |
5. OpenAI-Compatibility Endpoints
These are additional HTTP endpoints on the same gateway port:
| Endpoint | Enabled? | Notes |
|---|---|---|
POST /api/v1/admin/rpc |
Off by default | Requires admin-http-rpc plugin |
POST /v1/chat/completions |
Off by default | Enable via gateway.http.endpoints.chatCompletions.enabled |
POST /v1/responses |
Off by default | Enable via gateway.http.endpoints.responses.enabled |
None of these are enabled in the current config.
6. Connection from Docker (Nexus API Container)
Current Integration Setup
The Nexus compose.yaml already includes the full integration infrastructure:
api:
extra_hosts:
- host.docker.internal:host-gateway
environment:
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://host.docker.internal:18789}
Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-}
Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-}
The API container:
- Uses
host.docker.internal:18789to reach the Gateway via the Docker host - Has
extra_hostsconfigured forhost.docker.internal - Reads token/password from
.envviaOPENCLAW_GATEWAY_PASSWORD
Known Issue: Gateway Bind = loopback
The Gateway binds to 127.0.0.1 (gateway.bind: "loopback"). This means it only listens inside the gateway container's loopback interface.
| Scenario | Works? | Why |
|---|---|---|
Gateway with --network host |
✅ Yes | Process sees host's 127.0.0.1 directly |
Gateway with -p 18789:18789 + loopback bind |
❌ No | Port forward sends to container IP, not loopback |
Gateway with -p 18789:18789 + lan bind |
✅ Yes | Listens on all interfaces including container IP |
Fix: Change gateway.bind from "loopback" to "lan" (binds 0.0.0.0):
{
gateway: {
bind: "lan" // was "loopback"
}
}
Test command (from Nexus API container):
curl -s http://host.docker.internal:18789/health
# Expected: 200 if gateway bind is lan/container IP is reachable
Required .env Vars for Nexus
The Nexus project .env needs these values for gateway integration:
# OpenClaw Gateway integration
OPENCLAW_GATEWAY_PASSWORD=ieDmOjBiVfbbDM0ibrEebPAg
The compose.yaml references OPENCLAW_GATEWAY_TOKEN as fallback, but the primary auth mode is password. Either var works with Bearer auth.
7. Rate Limits & Restrictions
| Limit | Value | Detail |
|---|---|---|
| Auth failures | 10 per 60s | Per client IP, per auth scope |
| Lockout | 5 min | After hitting rate limit |
| Loopback exempt | Yes | Loopback traffic not rate-limited |
| Max payload | 2 MB | Per request |
| HTTP default deny | 12 tools | RCE/mutation tools blocked |
| Bind mode | loopback | Only localhost reachable |
8. Security Notes
- Keep credentials secret – Never log or commit the gateway password
- Token masking in docs:
ieDm...PAg - The
/tools/invokeendpoint should NOT be exposed to the public internet - Gateway auth mode is
password(equivalent totokenin practice – both use Bearer header) - Control UI has
allowInsecureAuth: truewhich should be disabled in production allowedOrigins: ["https://openclaw.noveria.net"]should be reviewed
9. Example curl Commands (for reference)
# Health check
curl http://127.0.0.1:18789/health
# Session status
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
-H "Authorization: Bearer <PASSWORD>" \
-H "Content-Type: application/json" \
-d '{"tool":"session_status","args":{}}'
# List sessions
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
-H "Authorization: Bearer <PASSWORD>" \
-H "Content-Type: application/json" \
-d '{"tool":"sessions_list","args":{"kinds":["main","subagent"]}}'
# Session history
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
-H "Authorization: Bearer <PASSWORD>" \
-H "Content-Type: application/json" \
-d '{"tool":"sessions_history","args":{"sessionKey":"iris-main","limit":10}}'
# Memory search
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
-H "Authorization: Bearer <PASSWORD>" \
-H "Content-Type: application/json" \
-d '{"tool":"memory_search","args":{"query":"nexus","maxResults":5}}'
# Subagents list
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
-H "Authorization: Bearer <PASSWORD>" \
-H "Content-Type: application/json" \
-d '{"tool":"subagents","args":{"action":"list"}}'
Replace <PASSWORD> with the actual gateway password.