# 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 ```bash Authorization: Bearer ``` All requests to `POST /tools/invoke` must include the `Authorization: Bearer` header with the gateway password from `gateway.auth.password`. ### Configuration (from openclaw.json) ```json5 { 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 on `127.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 ` **Max payload size:** 2 MB ### Request body structure ```json { "tool": "", "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): ```json5 { 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:** ```json { "tool": "session_status", "args": {} } ``` **Expected response structure:** ```json { "ok": true, "result": { "sessionKey": "main", "agentId": "iris", "modelId": "openai/gpt-5.4", "channel": "webchat", "created": "", "active": true, "toolsAvailable": ["read", "write", "edit", "exec", ...], "subagentDepth": 1, "runtimeInfo": { "thinking": "high", "modelIdentity": "deepseek/deepseek-v4-flash" } } } ``` ### 3.2 `sessions_list` **Request:** ```json { "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:** ```json { "tool": "subagents", "args": { "action": "list" } } ``` **Expected response:** List of configured subagents for the active session. ### 3.4 `sessions_history` **Request:** ```json { "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) - `timestamp` - `tool_calls` (if applicable) ### 3.5 `memory_search` **Request:** ```json { "tool": "memory_search", "args": { "query": "...", "maxResults": 5 } } ``` **Expected response:** ```json { "ok": true, "result": [ { "content": "...", "path": "memory/YYYY-MM-DD.md", "score": 0.95, "metadata": { "...": "..." } } ] } ``` ### 3.6 Health Check (non-tools/invoke) **Request:** ```bash GET http://127.0.0.1:18789/health ``` **Expected response:** "OK" or `{ "status": "ok" }` --- ## 4. Data Structures for Dashboard Integration ### Tool Call Response - Success ```json { "ok": true, "result": } ``` ### Tool Call Response - Error ```json { "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: ```yaml 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:18789` to reach the Gateway via the Docker host - Has `extra_hosts` configured for `host.docker.internal` - Reads token/password from `.env` via `OPENCLAW_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`): ```json5 { gateway: { bind: "lan" // was "loopback" } } ``` **Test command (from Nexus API container):** ```bash 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: ```bash # 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/invoke` endpoint should NOT be exposed to the public internet - Gateway auth mode is `password` (equivalent to `token` in practice – both use Bearer header) - Control UI has `allowInsecureAuth: true` which should be disabled in production - `allowedOrigins: ["https://openclaw.noveria.net"]` should be reviewed --- ## 9. Example curl Commands (for reference) ```bash # 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 " \ -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 " \ -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 " \ -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 " \ -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 " \ -H "Content-Type: application/json" \ -d '{"tool":"subagents","args":{"action":"list"}}' ``` Replace `` with the actual gateway password.