OpenClaw OpenAI-compatible HTTP API
The disabled-by-default chat completions, models and embeddings endpoints, the full-operator security boundary, the agent-first model contract, session keys from the user field and the tool-calling and streaming contracts
Anything that speaks the OpenAI Chat Completions protocol can talk to an OpenClaw agent, because the gateway serves a small compatible surface on the same port as its WebSocket. It is off by default, it is full operator access when on, and its model field means something different from what your client thinks. Here is the contract as the docs describe it.
What it serves and who it trusts
- Once gateway.http.endpoints.chatCompletions is enabled the gateway serves POST /v1/chat/completions, GET /v1/models, GET on a single model id and POST /v1/embeddings on the gateway port; the responses endpoint is enabled separately, and every request runs as a normal gateway agent run on the same codepath as the agent command, so routing, permissions and config match your gateway.
- A valid gateway token or password for this endpoint is equivalent to an owner or operator credential, not a per-user scope: shared-secret bearer auth ignores any x-openclaw-scopes header and restores the full default operator scope set, and treats chat turns as owner-sender turns; trusted-proxy or private no-auth ingress honors x-openclaw-scopes when present and needs operator.admin for owner-level controls.
- Auth follows the gateway mode: bearer token or password from the config or the environment variable, an identity-aware proxy in trusted-proxy mode (same-host loopback proxies need allowLoopback), or no header on private ingress; same-host callers bypassing a trusted proxy can fall back to the password unless forwarded-header evidence keeps them on the proxy path, and too many failed attempts return 429 with Retry-After when a rate limit is configured.
- The docs prefer this endpoint over a new built-in channel when the integration is just another operator surface, prefer WebChat or the gateway protocol with the paired-device flow for native mobile clients so no shared token ships on the device, and a channel plugin when integrating an external messaging network with its own users, rooms and transport.
OpenClaw treats the OpenAI model field as an agent target, not a raw provider model id.
Models are agents, sessions come from user
openclaw and openclaw/default route to the configured default agent, openclaw/ followed by the agent id or agent: followed by it to a specific agent, and /v1/models lists those agent targets, not provider models and not sub-agents. The x-openclaw-model header overrides the backend model for the selected agent, directly for shared-secret callers and only with operator.admin for identity-bearing ones; x-openclaw-session-key routes explicitly and is rejected with a 400 when it uses a reserved namespace such as subagent, cron or acp; x-openclaw-message-channel sets a synthetic ingress channel for channel-aware prompts. By default each request is stateless with a fresh session key; an OpenAI user string derives a stable key so repeated calls share a session, so reuse one value per conversation thread and avoid account-level identifiers unless several devices should share one session. Continuing an incognito session explicitly needs effective operator.admin, and the profile-backed response hides the target as a not-found forbidden error.
Tools, limits and streaming
- Function tools and tool_choice (auto, none, required or a pinned function) are supported, with tool-role follow-up messages bound by tool_call_id; max_completion_tokens is the current cap with max_tokens as the legacy alias, and temperature, top_p, the penalties, seed and up to four stop sequences are validated then forwarded best-effort, the wire names chosen by the provider transport.
- Requests are limited to 20 MB of body, 8 image_url parts from the latest user message and 20 MB of decoded image data; URL-sourced images are rejected unless images.allowUrl is on, with a host allowlist, allowed MIME types, 10 MB per image, 3 redirects and a 10 s timeout by default, HEIC and HEIF normalized to JPEG, and an allowlisted hostname never bypasses private-IP blocking.
- With stream true the events arrive as data lines ending in DONE, tool calls as incremental delta chunks then a tool_calls finish reason, a usage chunk when include_usage is set; a failed run returns an error rather than a completion, a streaming failure emits an error object then DONE, and a disconnecting client cancels the source downloads and the agent run.
The OpenClaw API is the wider gateway API post and OpenClaw operator scopes explains the operator scope set this endpoint restores or narrows.
The Open WebUI recipe
The quick setup is a base URL of the gateway host and port with /v1, host.docker.internal from Docker on macOS, the gateway bearer token as API key and openclaw/default as model; if a curl of /v1/models with the bearer returns openclaw/default, most Open WebUI setups connect with the same base URL and token. The examples then show a stable session with a conv-prefixed user value, a streaming call with x-openclaw-model pinning a provider model, fetching one model with the slash URL-encoded, and embeddings with an embedding model in the header and an optional dimensions integer that overrides the agent memory output dimensionality. OpenClaw remote access covers reaching the port safely and OpenClaw gateway security controls the controls that guard it.
On Diali
On Diali the gateway sits behind the platform ingress with the runtime configuration generated from the dashboard, so exposing this surface is a configuration decision rather than a port to open. Hosted OpenClaw on Diali describes the hosted assistant and Diali pricing the plans it ships in.
- Off by default; on, a token is owner access.
- The model field names an agent; user names the session.
- Loopback, tailnet or private ingress, never the public internet.
Stop reading about it, build one
Set up an agent, pick a channel, and have it working inside the app you already keep open.
