External App Integration via Gateway Protocol
This page explains how external scripts, dashboards, CI jobs, and IDE extensions interact with OpenClaw through the Gateway protocol. It covers WebSocket transport and RPC methods for initiating runs and streaming events.
Read this when
- You are building an external app, script, dashboard, CI job, or IDE extension that talks to OpenClaw
- You are choosing between Gateway RPC and the Plugin SDK
- You are integrating with Gateway agent runs, sessions, events, approvals, models, or tools
- You are pairing a hosting controller with an external wake scheduler
External applications interact with OpenClaw through the Gateway protocol, which combines WebSocket transport with RPC methods. This approach is suitable when a script, dashboard, CI job, IDE extension, or other process needs to initiate agent runs, stream events, wait for results, cancel operations, or inspect Gateway resources.
Note
For npm packages, device pairing, reconnect recovery, history, subscriptions, and approvals, begin with Building a Gateway client. If your application manages the Gateway as a child process, also consult Embedding OpenClaw. During the initial package rollout, npm may return
E404until the first package-bearing OpenClaw release is published.
Note
This page targets code running outside the OpenClaw process. Plugin code executing inside OpenClaw should use the documented
openclaw/plugin-sdk/*subpaths instead.
What is available today
| Surface | Status | Use it for |
|---|---|---|
| Gateway client guide | Release train | npm packages, auth, reconnect, history, events, approvals, and version policy. |
| Embedding guide | Release train | Child-process environment, readiness, lifecycle, recovery, RPC ownership, and packaging. |
| Gateway protocol | Ready | WebSocket transport, connect handshake, auth scopes, protocol versioning, and events. |
| Gateway RPC reference | Ready | Current Gateway methods for agents, sessions, tasks, models, tools, artifacts, and approvals. |
openclaw agent | Ready | One-shot script integration when shelling out to the CLI is enough. |
openclaw message | Ready | Sending messages or channel actions from scripts. |
Recommended path
- Run or discover a Gateway.
- Connect over the Gateway protocol.
- Call documented RPC methods from Gateway RPC reference.
- Pin the OpenClaw version you test against.
- Recheck the RPC reference when upgrading OpenClaw.
For agent runs, begin with the agent RPC and combine it with agent.wait to obtain a
terminal result. For persistent conversation state, use the sessions.* methods.
For UI integrations, subscribe to Gateway events and render only the event
families your application understands.
Cooperative host suspension
Hosting controllers that freeze or snapshot a running process can use the host-neutral suspension handshake:
- Stop admitting external ingress controlled by the host.
- Call
gateway.suspend.preparewith a stable, uniquerequestId. - If the response is
busy, keep the process running and retry later. - If it is
ready, save the returnedsuspensionId, then freeze or snapshot the process beforeexpiresAtMs. - After thaw, or if suspension is abandoned, call
gateway.suspend.resumewith thatsuspensionIdover the existing WebSocket or Admin HTTP control path.
A prepared Gateway rejects new WebSocket handshakes. A WebSocket controller must keep its authenticated connection open across the host operation. If that cannot be guaranteed, enable and use the Admin HTTP RPC plugin before preparing. If the control path is lost, wait for the two-minute lease to expire before reconnecting; expiry reopens admission automatically.
The RPC contract is:
gateway.suspend.prepare,operator.admin; params{ "requestId": "stable-host-operation-id" }gateway.suspend.status,operator.read; params{ "suspensionId": "id-from-prepare" }gateway.suspend.resume,operator.admin; params{ "suspensionId": "id-from-prepare" }
IDs are trimmed, must contain a non-whitespace character, and are limited to
128 characters. A busy prepare result has status: "busy", reason,
retryAfterMs, activeCount, and blockers. A ready result has this shape:
{
"status": "ready",
"suspensionId": "2c3f...",
"expiresAtMs": 1770000000000,
"activeCount": 0,
"blockers": []
}
Status returns {"status":"running"} or a ready result with expiresAtMs.
Resume returns {"ok":true,"status":"running","resumed":true}; repeating it
after a successful resume returns resumed: false.
A competing request ID or transient scheduler-resume failure returns retryable
UNAVAILABLE with retryAfterMs. During scheduler recovery, prepare, status,
and resume all return that error, the Gateway remains not-ready and
fail-closed, and the host must not freeze or snapshot it. OpenClaw retries the
scheduler automatically and reopens admission only after recovery succeeds. A
mismatched resume ID returns INVALID_REQUEST. Prepare shares the Gateway's
control-plane write budget of three attempts per minute; honor the returned
retry delay. WebSocket clients are bucketed by device and IP. Admin HTTP
controllers are bucketed by resolved client IP, so controllers behind one
proxy can share a budget.
Preparation is refuse-only: OpenClaw closes new root/session/command admission,
pauses automatic cron ticks, and inspects work synchronously. If anything is
active, it resumes the scheduler and reopens admission before returning
busy; it does not interrupt or drain that work. A ready lease lasts two
minutes. Repeating prepare with the same requestId renews it; expiry resumes
the scheduler before reopening admission.
Restart emission that becomes due during a ready lease waits until the lease
resumes; an in-flight restart makes preparation return busy.
When /healthz is ready, it stays active and /readyz gives back 503. Responses from local or authenticated readiness checks include gateway-draining; remote unauthenticated probes get only { "ready": false }. The HTTP health probe, methods for suspending existing WebSocket connections, and a previously enabled Admin HTTP RPC route all remain accessible. Other RPCs produce retryable UNAVAILABLE. Built-in HTTP user routes and standard plugin HTTP routes (including OpenAI compatible APIs, tool and session operations, node watches, and configured hooks) respond with 503 accompanied by error.code: "gateway_unavailable". New WebSocket upgrades owned by plugins also return 503; this applies to upgrade ownership, not to work performed later over an already established plugin socket.
This handshake does not buffer incoming messages, halt third-party channel transports, or manage the hosting platform. Before preparation begins, the host must fence its ingress and remains responsible for wake, snapshot/freeze, and stop operations. activeCount represents the total tracked work count, while blockers holds the non-zero category counts together with bounded task details. This mechanism is not a general process quiescence barrier. A background-exec blocker is aggregate only: command text, process IDs, output, and session or scope identifiers are never transmitted across the protocol. Channel health, maintenance, cache refresh, established plugin WebSocket sessions, and unregistered plugin owned background work may all stay active. The hosting platform must consistently freeze or snapshot the entire process tree and its filesystem; this first contract cannot prove that unregistered work is idle.
Tip
For host wake scheduling, keep the OpenClaw facing part inside an in-process plugin and project idempotent full snapshots to the external host adapter. The hosting controller must not import the Plugin SDK or reconstruct cron state from event deltas. Refer to Safe external cron projection.
App code vs plugin code
Choose Gateway RPC when code lives outside OpenClaw:
- Node scripts that start or observe agent runs
- CI jobs that call a Gateway
- dashboards and admin panels
- IDE extensions
- external bridges that do not need to become channel plugins
- integration tests using fake or real Gateway transports
Choose the Plugin SDK when code runs inside OpenClaw:
- provider plugins
- channel plugins
- tool or lifecycle hooks
- agent harness plugins
- trusted runtime helpers
External apps must not import openclaw/plugin-sdk/*; those subpaths are intended only for plugins loaded by OpenClaw.