OpenClaw Protocol API Reference
Overview
ClawDesk communicates with an OpenClaw server using a custom WebSocket-based JSON-RPC protocol (v3). Messages are exchanged as JSON frames with three types: req (client requests), res (server responses), and event (server-pushed events).
Frame Types
Request Frame
{
type: 'req'
id: string // Unique request ID (incrementing counter)
method: string // RPC method name
params?: any // Method parameters
}
Response Frame
{
type: 'res'
id: string // Matches request ID
ok: boolean // Success indicator
payload?: any // Response data (when ok=true)
error?: {
code: string
message: string
details?: any
}
}
Event Frame
{
type: 'event'
event: string // Event type
payload?: any // Event data
}
Connection & Authentication
Handshake Flow
- Client opens WebSocket to
wss://{server}/ws - Server sends
connect.challengeevent withnonce - Client sends
reqwith methodconnectand auth credentials - Server responds with
hello-okpayload
connect
Authenticates the client with the server.
Parameters:
{
token?: string // Gateway token (when authMode='token')
password?: string // Password (when authMode='password')
mode: 'token' | 'password'
clientId: string // Stable client identifier
device?: { // Ed25519 device identity (optional)
id: string // SHA-256(publicKey)
publicKey: string // base64url encoded
signature: string // Challenge signature (base64url)
signedAt: number // Timestamp (ms)
nonce: string // Echo of server nonce
}
}
Response Payload (hello-ok):
{
auth?: {
deviceToken?: string // Server-issued device token for reconnects
}
}
Error Codes:
NOT_PAIRED— Device needs pairing approvalDEVICE_IDENTITY_STALE— Cached device identity is invalid
RPC Methods
Sessions
sessions.list
Lists all active sessions.
Parameters:
{
includeDerivedTitles: true
includeLastMessage: true
limit: 50
}
Response: Session[] or { sessions: Session[] }
interface Session {
id: string
key: string
title: string
agentId?: string
createdAt: string // ISO 8601
updatedAt: string // ISO 8601
lastMessage?: string
spawned?: boolean
parentSessionId?: string
cron?: boolean
}
sessions.delete
Deletes a session.
Parameters: { key: string }
sessions.patch
Updates session metadata.
Parameters: { key: string, label?: string }
sessions.spawn
Creates a subagent session.
Parameters: { agentId: string, prompt?: string }
Response: { session: Session } with spawned: true
sessions.usage
Returns usage statistics per session.
Parameters: { days?: number, limit?: number }
Chat
chat.send
Sends a message in a session.
Parameters:
{
message: string
sessionKey: string
idempotencyKey: string // UUID for deduplication
thinking?: 'low' // Enable extended thinking
attachments?: Array<{
type?: string
mimeType?: string
fileName?: string
content: string // Base64 or text content
}>
}
Response: { sessionKey?: string } — Server may assign a different canonical key.
chat.history
Fetches message history for a session.
Parameters: { sessionKey: string }
Response: Array of message objects with content blocks:
{
id: string
role: 'user' | 'assistant' | 'system'
content: string | ContentBlock[]
timestamp: string
thinking?: string
}
Content block types:
{ type: 'text', text: string }{ type: 'thinking', thinking: string }{ type: 'toolCall', toolCallId, name, args }{ type: 'toolResult', toolCallId, result }{ type: 'image', url?, data?, mimeType? }
chat.abort
Cancels an ongoing chat stream.
Parameters: { sessionKey: string }
Agents
agents.list
Lists all configured agents.
Response: Agent[] or { agents: Agent[] }
interface Agent {
id: string
name: string
description?: string
status: 'online' | 'offline' | 'busy'
avatar?: string
emoji?: string
theme?: string
model?: string
thinkingLevel?: string
timeout?: number
configured?: boolean
}
agent.identity.get
Fetches agent identity metadata (name, emoji, avatar).
Parameters: { agentId: string }
Response: { name?, emoji?, avatar?, avatarUrl? }
agents.files.list
Lists files in an agent’s workspace.
Parameters: { agentId: string }
Response: { workspace: string, files: AgentFile[] }
interface AgentFile {
name: string
path: string
missing: boolean
size?: number
updatedAtMs?: number
}
agents.files.get
Reads a single agent file.
Parameters: { agentId: string, name: string }
Response: { file: { content?: string, missing: boolean } }
agents.files.set
Writes or updates an agent file.
Parameters: { agentId: string, name: string, content: string }
Configuration
config.get
Reads the full server configuration.
Response:
{
config: object // Full server configuration
hash: string // Hash for conflict detection
}
config.patch
Patches server configuration (triggers server restart).
Parameters:
{
raw: string // JSON-stringified merge patch
baseHash: string // Hash from config.get for conflict detection
}
Merge patch semantics:
- Plain objects: recursively merged
- Arrays: replaced entirely
nullvalues: delete the key
Skills
skills.status
Lists all skills with extended metadata.
Response: Skill[] or { skills: Skill[] }
interface Skill {
id: string // skillKey
name: string
description: string
triggers: string[]
enabled?: boolean
emoji?: string
homepage?: string
source?: string
bundled?: boolean
filePath?: string
eligible?: boolean
always?: boolean
requirements?: {
bins: string[]
anyBins: string[]
env: string[]
config: string[]
os: string[]
}
missing?: { /* same shape */ }
install?: Array<{
id: string
kind: string
label: string
bins?: string[]
}>
}
skills.update
Enables or disables a skill.
Parameters: { skillKey: string, enabled: boolean }
skills.install
Installs a skill dependency.
Parameters: { name: string, installId: string, timeoutMs: 60000 }
Cron Jobs
cron.list
Lists all cron jobs.
Response: CronJob[] or { cronJobs: CronJob[] }
interface CronJob {
id: string
name: string
schedule: string
scheduleRaw?: CronScheduleType
sessionTarget?: 'main' | 'isolated'
wakeMode?: 'next-heartbeat' | 'now'
payload?: CronPayload
delivery?: CronDelivery
agentId?: string | null
deleteAfterRun?: boolean
nextRun?: string
status: 'active' | 'paused'
description?: string
content?: string
state?: CronJobState
enabled?: boolean
}
cron.get
Fetches full details for a single cron job.
Parameters: { id: string }
cron.add
Creates a new cron job.
Parameters: Full cron job definition object.
cron.update
Updates a cron job.
Parameters: { id: string, ...updates }
cron.remove
Deletes a cron job.
Parameters: { id: string }
cron.run
Executes a cron job immediately.
Parameters: { id: string }
Nodes & Devices
node.list
Lists all connected nodes.
Response: { ts: number, nodes: Node[] }
interface Node {
nodeId: string
displayName?: string
platform?: string
version?: string
coreVersion?: string
uiVersion?: string
deviceFamily?: string
modelIdentifier?: string
remoteIp?: string
caps: string[]
commands: string[]
pathEnv?: string
permissions?: Record<string, boolean>
connectedAtMs?: number
paired: boolean
connected: boolean
}
exec.approvals.get
Reads the global exec approvals configuration.
Response:
{
path: string
exists: boolean
hash: string
file: {
version: number
socket?: { path?: string; token?: string }
defaults?: {
security?: 'deny' | 'allowlist' | 'full'
ask?: 'off' | 'on-miss' | 'always'
askFallback?: 'deny' | 'allowlist' | 'full'
autoAllowSkills?: boolean
}
agents?: Record<string, {
security?: string
ask?: string
askFallback?: string
autoAllowSkills?: boolean
allowlist?: Array<{
pattern: string
lastUsedAt?: number
lastUsedCommand?: string
}>
}>
}
}
exec.approvals.set
Updates the global exec approvals configuration.
Parameters: { file: ExecApprovalsFile, baseHash: string }
exec.approvals.node.get / exec.approvals.node.set
Same as above but scoped to a specific node.
Additional parameter: { nodeId: string }
device.pair.list
Lists pending pairing requests and paired devices.
Response:
{
pending: Array<{
requestId: string
deviceId: string
displayName?: string
platform?: string
roles?: string[]
scopes?: string[]
remoteIp?: string
ts: number
}>
paired: Array<{
deviceId: string
displayName?: string
platform?: string
roles?: string[]
scopes?: string[]
remoteIp?: string
tokens?: Record<string, {
count: number
oldestCreatedAt?: number
newestCreatedAt?: number
newestRotatedAt?: number
}>
}>
}
device.pair.approve / device.pair.reject
Approves or rejects a pending pairing request.
Parameters: { requestId: string }
device.pair.remove
Removes a paired device.
Parameters: { deviceId: string }
device.token.rotate
Rotates a device’s auth token.
Parameters: { deviceId: string, role: string, scopes?: string[] }
device.token.revoke
Revokes a device’s auth token.
Parameters: { deviceId: string, role: string }
Usage & Features
usage.status
Returns server usage status and limits.
usage.cost
Returns cost tracking information.
tts.status / tts.providers
Get text-to-speech status and available providers.
tts.enable / tts.disable
Toggle text-to-speech.
tts.setProvider
Set TTS provider. Parameters: { provider: string }
voicewake.get / voicewake.set
Get or configure voice wake word detection.
Server Events
Chat Events
chat (state: “delta”)
Streaming text chunk for a session.
{
event: 'chat'
payload: {
state: 'delta'
sessionKey?: string
delta?: string // Incremental text
message?: {
content: string | ContentBlock[]
}
}
}
chat (state: “final”)
Complete message with canonical data.
{
event: 'chat'
payload: {
state: 'final'
sessionKey?: string
message: {
id: string
role: string
content: string | ContentBlock[]
timestamp: string
thinking?: string
}
}
}
Agent Events
agent (stream: “assistant”)
Agent text output.
{
event: 'agent'
payload: {
stream: 'assistant'
sessionKey?: string
data: {
text?: string // Cumulative text
delta?: string // Incremental text
runId?: string
}
}
}
agent (stream: “tool”)
Tool call execution.
{
event: 'agent'
payload: {
stream: 'tool'
sessionKey?: string
data: {
toolCallId: string
name: string
phase: 'start' | 'result'
args?: object
result?: string
meta?: string
}
}
}
agent (stream: “lifecycle”)
Agent lifecycle events.
{
event: 'agent'
payload: {
stream: 'lifecycle'
sessionKey?: string
data: {
state?: 'complete' // Stream finished
phase?: 'end' | 'error'
runId?: string
}
}
}
Extended Thinking Events
{
event: 'agent'
payload: {
stream: 'thinking'
sessionKey?: string
data: {
text: string
cumulative?: boolean
}
}
}
Presence Events
{
event: 'presence'
payload: {
agentId: string
status: 'online' | 'offline' | 'busy'
}
}
Compaction Events
{
event: 'agent'
payload: {
stream: 'lifecycle'
data: {
phase: 'compaction_start' | 'compaction_end'
willRetry?: boolean
}
sessionKey?: string
}
}
Session Key Format
Session keys follow the pattern: agent:{agentId}:{identifier}
| Pattern | Description |
|---|---|
agent:main:{uuid} |
Main agent session |
agent:{name}:{uuid} |
Custom agent session |
agent:{name}:main |
Agent’s main/system session |
agent:{name}:cron:{job} |
Cron-triggered session |
agent:{name}:subagent:{uuid} |
Spawned subagent session |
Error Handling Conventions
- RPC calls timeout after 30 seconds by default
- Connection timeout: 15 seconds
- Health check interval: 15 seconds (via
skills.status) - Auto-reconnect: exponential backoff up to 30 seconds, max 20 attempts
- Config patches require hash match for optimistic conflict detection
- Silent error swallowing with
console.warnfor non-critical failures