Skip to main content

Gateway API reference

The WednesdayAI gateway exposes:
  1. WebSocket control plane - all clients (CLI, web UI, mobile apps, nodes) connect here
  2. HTTP tools endpoint - invoke agent tools directly without a full agent run
  3. OpenAI-compatible endpoints - POST /v1/chat/completions and POST /v1/responses
All endpoints share the same port (18789 by default) via HTTP/WebSocket multiplexing.

Authentication

All endpoints use the gateway auth configuration:
Auth modeHow to authenticate
token (default)Authorization: Bearer <OPENCLAW_GATEWAY_TOKEN>
passwordAuthorization: Bearer <OPENCLAW_GATEWAY_PASSWORD>
trusted-proxyDelegated to upstream proxy via the configured user header
noneNo auth (loopback-only setups)
Too many failed auth attempts returns HTTP 429 with a Retry-After header (tunable via gateway.auth.rateLimit).

WebSocket protocol

The WebSocket control plane is the primary integration surface. All CLI commands, the web control panel, and mobile nodes use this protocol. Connection: ws://localhost:18789 (or wss:// with TLS)

Handshake

The gateway sends a challenge before accepting the connection: Gateway -> Client (challenge):
{
  "type": "event",
  "event": "connect.challenge",
  "payload": { "nonce": "...", "ts": 1737264000000 }
}
Client -> Gateway (connect request):
{
  "type": "req",
  "id": "req-1",
  "method": "connect",
  "params": {
    "minProtocol": 3,
    "maxProtocol": 3,
    "client": { "id": "my-client", "version": "1.0.0", "platform": "linux", "mode": "operator" },
    "role": "operator",
    "scopes": ["operator.read", "operator.write"],
    "auth": { "token": "your-gateway-token" },
    "locale": "en-US"
  }
}
Gateway -> Client (success):
{
  "type": "res",
  "id": "req-1",
  "ok": true,
  "payload": {
    "type": "hello-ok",
    "protocol": 3,
    "policy": { "tickIntervalMs": 15000 },
    "auth": { "deviceToken": "...", "role": "operator", "scopes": ["operator.read", "operator.write"] }
  }
}
The deviceToken in the response can be saved and passed as auth.token on subsequent connections to skip full re-authentication. The protocol version is currently 3.

Request/response pattern

After handshake, all communication uses type: "req" with an id for correlation and type: "res" responses:
{ "type": "req", "id": "req-2", "method": "sessions.list", "params": {} }
{ "type": "res", "id": "req-2", "ok": true, "payload": { "sessions": [] } }
On error, ok is false and error is set:
{ "type": "res", "id": "req-2", "ok": false, "error": { "code": "NOT_FOUND", "message": "Session not found" } }

RPC methods

The table below is not exhaustive. The gateway registers dozens of methods and plugins can add more. To enumerate or call any method from the CLI, use openclaw gateway call <method> --params '<json>'. There is no public “list methods” RPC - the authoritative surface is the gateway source and the gateway call helper.
Common methods, grouped by namespace:
NamespaceMethods
Handshakeconnect (must be first)
Configconfig.get, config.set, config.patch, config.apply, config.schema
Sessionssessions.list, sessions.preview, sessions.resolve, sessions.patch, sessions.reset, sessions.delete, sessions.compact, sessions.usage
Chatchat.send, chat.history, chat.inject, chat.abort
Channelschannels.status, channels.logout
Logs / healthlogs.tail, usage.status, usage.cost
Croncron.list, cron.status, cron.add, cron.update, cron.remove, cron.run, cron.runs
System / updateupdate.run
Pairing (devices)device.pair.list, device.pair.approve, device.pair.reject, device.pair.remove, device.token.rotate, device.token.revoke
Nodesnode.list, node.describe, node.invoke, node.event, node.rename, node.pair.list, node.pair.approve, node.pair.reject, node.pair.request, node.pair.verify
Modelsmodels.list
Memorydoctor.memory.status
Browserbrowser.request
Approvalsexec.approvals.get, exec.approvals.set, exec.approval.request, exec.approval.resolve
Secretssecrets.reload, secrets.resolve
Skillsskills.status, skills.install, skills.update, skills.bins
Voice / TTStts.status, tts.enable, tts.disable, tts.providers, tts.setProvider, tts.convert, talk.config, talk.mode
Wizardwizard.start, wizard.next, wizard.status, wizard.cancel
openclaw gateway status, openclaw gateway health, and openclaw gateway probe are CLI helpers that establish a connection and read the handshake/health payload - they are not single RPC method names. Likewise tools.invoke is exposed over HTTP (POST /tools/invoke), not as a control-plane method.

Config RPC rate limiting

config.apply and config.patch are rate-limited to 3 requests per 60 seconds per deviceId+clientIp. When limited, the call returns UNAVAILABLE with retryAfterMs. Both require a baseHash (from config.get) to prevent concurrent conflicting writes. Restarts are coalesced with a 30-second cooldown.

HTTP: Tool invocation

POST /tools/invoke - invoke a single agent tool directly. Always enabled; gated by gateway auth and tool policy. Maximum payload size: 2 MB
curl -X POST http://localhost:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "tool": "sessions_list", "args": {}, "sessionKey": "main" }'
FieldTypeRequiredDescription
toolstringYesTool name to invoke
actionstringNoShorthand mapped into args if the tool supports action
argsobjectNoTool-specific arguments
sessionKeystringNoTarget session key (defaults to main session)
Tool availability is filtered through the tool policy chain (tools.*, agents.<id>.tools.*, and the HTTP-specific gateway.tools.deny/gateway.tools.allow overrides). If a tool is not allowed, the endpoint returns HTTP 404.

HTTP: OpenAI-compatible Chat Completions

POST /v1/chat/completions - drop-in replacement for the OpenAI Chat Completions API. Runs a full gateway agent turn. Disabled by default. Enable with gateway.http.endpoints.chatCompletions.enabled: true.
curl -X POST http://localhost:18789/v1/chat/completions \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openclaw:main",
    "messages": [ { "role": "user", "content": "What is the current time?" } ],
    "stream": false
  }'
Target a specific agent via the model string (openclaw:<agentId>) or headers:
x-openclaw-agent-id: main
x-openclaw-session-key: agent:main:whatsapp:dm:+15555550123
Tool calls, streaming (stream: true), and multi-turn conversations are supported.

HTTP: OpenAI-compatible Responses

POST /v1/responses - implements the OpenAI Responses API shape. Runs a full gateway agent turn and supports URL/file/image inputs. Disabled by default. Enable with gateway.http.endpoints.responses.enabled: true.
curl -X POST http://localhost:18789/v1/responses \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openclaw:main",
    "input": "Summarise https://example.com/report.pdf"
  }'
URL-input fetching is hardened via config. Set allowlists and limits before enabling URL fetch:
{
  gateway: {
    http: {
      endpoints: {
        responses: {
          enabled: true,
          maxUrlParts: 16,
          files: {
            allowUrl: true,
            urlAllowlist: ["https://example.com"],
            maxBytes: 10485760,
            pdf: { maxPages: 50, minTextChars: 16 },
          },
          images: { allowUrl: true, urlAllowlist: ["https://example.com"], maxBytes: 10485760 },
        },
      },
    },
  },
}
Both /v1/chat/completions and /v1/responses have full operator access to the gateway. A valid token here is equivalent to owner/operator credentials. Keep them on loopback or a private network - do not expose them to the public internet.

Control-UI HTTP surface and security headers

When gateway.controlUi.enabled is true, the gateway also serves the control panel and its assets over HTTP on the same port. Browser access is gated by the same auth modes plus device authorisation and origin checks (gateway.controlUi.allowedOrigins). For HTTPS deployments behind a reverse proxy you control, add HSTS:
{
  gateway: {
    http: {
      securityHeaders: { strictTransportSecurity: "max-age=63072000; includeSubDomains" },
    },
  },
}
Set strictTransportSecurity: false to omit the header. See Trusted proxy auth for TLS termination guidance.

Node connection (mobile/desktop nodes)

Nodes (iOS, Android, macOS app in node mode) connect with role: "node" and advertise their capabilities:
{
  "type": "req",
  "id": "req-1",
  "method": "connect",
  "params": {
    "role": "node",
    "caps": ["camera", "canvas", "screen", "location", "voice"],
    "commands": ["camera.snap", "canvas.navigate"],
    "auth": { "token": "node-device-token" }
  }
}
After connecting, the node listens for node.* RPC calls dispatched by the gateway agent and returns results. Approve pending nodes with openclaw nodes approve <requestId> (RPC: node.pair.approve).

See also