Agents API
Create, manage, and interact with agents.
All agent endpoints that require authentication are scoped to the authenticated user’s data through
row-level security. You can only access agents that belong to your account.
List agents
Returns all agents owned by the authenticated user. When no session is present, returns an empty list instead of a 401 error.
Response (backend)
The backend returns a flat array of agent objects:
[
{
"id": "agent_123",
"status": "active",
"created": "2026-03-01T00:00:00Z",
"subdomain": "agent_123.agents.localhost",
"url": "https://agent_123.agents.localhost"
}
]
| Field | Type | Description |
|---|
[].id | string | Agent identifier |
[].status | string | Current agent status |
[].created | string | ISO 8601 creation timestamp |
[].subdomain | string | Agent subdomain |
[].url | string | Agent URL |
Response (web proxy)
The web proxy wraps the response in an object:
{
"agents": [
{
"id": "agent_123",
"name": "My Agent",
"model": "claude-opus-4-6",
"status": "running",
"websocketUrl": "ws://openclaw-gateway:10000/agent/user_123",
"createdAt": "2026-03-01T00:00:00Z",
"updatedAt": "2026-03-01T12:00:00Z"
}
],
"count": 1,
"status": "ok"
}
| Field | Type | Description |
|---|
agents | array | List of agent objects owned by the authenticated user |
agents[].id | string | Agent identifier |
agents[].name | string | Agent name |
agents[].model | string | AI model assigned to the agent |
agents[].status | string | Current agent status |
agents[].websocketUrl | string | WebSocket URL for the agent gateway |
agents[].createdAt | string | ISO 8601 creation timestamp |
agents[].updatedAt | string | ISO 8601 last update timestamp |
count | number | Total number of agents returned |
status | string | Response status (ok) |
The backend and web proxy return different response shapes. The backend returns a flat array with created, subdomain, and url fields. The web proxy wraps the data in an agents key and includes name, model, websocketUrl, createdAt, and updatedAt fields.
Create agent
Creates a new agent with an auto-generated ID and stores its metadata on disk. Requires bearer token authentication (backend).
Request body
| Field | Type | Required | Description |
|---|
name | string | Yes | Agent name |
config | object | No | Agent configuration |
config.plan | string | No | Plan tier (for example, solo, collective, label, network) |
config.aiProvider | string | No | AI provider (for example, openrouter, anthropic) |
Response (201 Created)
{
"id": "agent_123",
"name": "My Agent",
"agentId": "agent_123",
"status": "pending",
"subdomain": "agent_123.agents.localhost",
"url": "https://agent_123.agents.localhost",
"createdAt": "2026-03-19T00:00:00Z"
}
Errors
| Code | Description |
|---|
| 400 | Agent name is required |
| 401 | Unauthorized |
| 500 | Failed to create agent |
Get agent
Requires authentication and ownership of the agent.
Response (backend)
The backend returns the agent object directly without a wrapper:
{
"id": "agent_123",
"status": "active",
"startedAt": "2026-03-01T00:00:00Z",
"plan": "solo",
"subdomain": "agent_123.agents.localhost",
"url": "https://agent_123.agents.localhost",
"openclawVersion": "2026.3.13",
"verified": false,
"verificationType": null,
"attestationUid": null,
"verifiedAt": null
}
Response (web proxy)
The web proxy wraps the agent in an object:
{
"agent": {
"id": "agent_123",
"status": "active",
"startedAt": "2026-03-01T00:00:00Z",
"plan": "solo",
"subdomain": "agent_123.agents.localhost",
"url": "https://agent_123.agents.localhost",
"openclawVersion": "2026.3.13",
"verified": false,
"verificationType": null,
"attestationUid": null,
"verifiedAt": null
},
"status": "ok"
}
The backend returns the agent object directly. The web proxy wraps it in an agent key and adds a top-level status field.
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 404 | Agent not found or not owned by user |
| 500 | Failed to fetch agent |
Update agent
Updates an agent’s metadata including plan, AI provider, and configuration. Requires bearer token authentication (backend).
Request body
| Field | Type | Required | Description |
|---|
plan | string | No | Plan tier |
aiProvider | string | No | AI provider |
config | object | No | Additional configuration |
Response
{
"id": "agent_123",
"plan": "collective",
"aiProvider": "anthropic",
"subdomain": "agent_123.agents.localhost",
"status": "active",
"message": "Agent updated"
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 404 | Agent not found |
| 500 | Failed to update agent |
Delete agent
Stops the agent’s container, releases its port, and removes its metadata. Requires bearer token authentication (backend).
Response
{
"id": "agent_123",
"deleted": true
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 500 | Failed to delete agent |
The backend uses best-effort cleanup (container stop, port release, metadata removal). If the agent does not exist, the operation succeeds silently and returns deleted: true.
Provision agent
POST /api/agents/provision
Provisions a new agent. Requires an active subscription unless the caller is an admin.
Provisioning requests may be processed asynchronously through the background task queue. The agent is created immediately with a provisioning status and transitions to running once the backend deployment endpoint confirms the deployment. If deployment fails, the status changes to error.
The provisioning endpoint calls POST /api/deployments on the backend to deploy the agent container. The request includes a 15-second timeout. When the model is set to claude-opus-4-6, the AI provider is automatically set to anthropic; otherwise it falls back to the provider specified in the agent configuration (default: openrouter). The plan sent to the backend defaults to label when no tier is specified.
Request body
| Field | Type | Required | Description |
|---|
name | string | Yes | Agent name |
model | string | No | AI model (default: claude-opus-4-6). Options: claude-opus-4-6, gpt-4, custom |
config | object | No | Agent configuration |
tier | string | No | Subscription tier hint. Options: starter, pro, enterprise. This value is forwarded to the backend as the plan field (mapped to solo, collective, label, network). When omitted, the backend deployment defaults to label. |
The web proxy enforces agent limits based on the subscription tier (starter: 1, pro: 3, enterprise: 100). The backend plan middleware enforces separate limits (label: 1, solo: 3, collective: 10, network: 100). The backend provisioning route (POST /api/provision) enforces its own limits (solo: 1, collective: 3, label: 10, network: unlimited). The limit cannot be overridden in the request body.
Admin bypass
Admin users (configured via ADMIN_EMAILS) are exempt from the following restrictions:
- Subscription requirement — admins can provision agents without an active subscription (the
402 error is not returned).
- Agent limit — admins receive an elevated agent slot limit instead of the plan-based cap.
Response (201 Created)
{
"success": true,
"agent": {
"id": "agent_789",
"name": "My Agent",
"status": "running",
"websocketUrl": "ws://openclaw-gateway:10000/agent/user_123",
"model": "claude-opus-4-6",
"createdAt": "2026-03-19T00:00:00Z"
}
}
Errors
| Code | Description |
|---|
| 400 | Agent name is required |
| 401 | Unauthorized |
| 402 | Active subscription required to provision agents |
| 429 | Agent limit reached for your plan (web proxy). Response includes current (agent count) and limit fields. Limits: starter 1, pro 3, enterprise 100. Users without a recognized plan default to a limit of 1. The backend returns 402 with code AGENT_LIMIT_REACHED for the same condition. |
| 500 | Failed to provision agent |
Clone agent
Creates a new agent by cloning an existing parent agent. Requires a verified payment proof on the Tempo chain (x402 protocol). The caller must pay 1.0 pathUSD to clone an agent.
This endpoint uses the
x402 Tempo protocol for payment verification. The payment must be completed on the Tempo chain (chain ID
4217) before calling this endpoint.
Request body
| Field | Type | Required | Description |
|---|
parentAgentId | string | Yes | ID of the agent to clone |
name | string | Yes | Name for the new agent |
specialization | string | No | Agent specialization. Options: general (default), ar, promo, booking, support, analytics |
paymentProof | object | Yes | On-chain payment proof (see below) |
generation | number | No | Current generation depth of the parent agent (default: 1). The cloned agent’s generation is set to this value plus one. |
Payment proof object
| Field | Type | Required | Description |
|---|
transactionHash | string | Yes | Transaction hash on Tempo chain (must start with 0x) |
amount | string | Yes | Payment amount (must be at least 1.0) |
currency | string | Yes | Must be pathUSD |
chainId | number | Yes | Must be 4217 (Tempo chain) |
from | string | Yes | Sender wallet address |
to | string | Yes | Recipient wallet address |
timestamp | number | Yes | Unix timestamp of the payment |
Response (200)
{
"success": true,
"agentId": "agent_1711234567890_a1b2c3",
"walletAddress": "0x1234...abcd",
"parentAgentId": "agent_789",
"generation": 2,
"transactionHash": "0xabc123...",
"specialization": "general",
"status": "provisioning",
"message": "Agent \"My Clone\" cloned successfully. Wallet funded with 0 pathUSD."
}
| Field | Type | Description |
|---|
success | boolean | Whether the clone was created |
agentId | string | Unique identifier for the new agent |
walletAddress | string | Wallet address assigned to the new agent |
parentAgentId | string | ID of the parent agent |
generation | number | Generation depth (number of hops from the root agent) |
transactionHash | string | Transaction hash from the payment proof |
specialization | string | Agent specialization |
status | string | Always provisioning on success |
message | string | Human-readable confirmation message |
Errors
| Code | Description |
|---|
| 400 | Missing required fields: parentAgentId, name, or paymentProof |
| 402 | Invalid payment proof — transaction not verified on Tempo chain |
| 500 | Clone failed |
Clone service health
Returns the clone service status and protocol configuration. No authentication required.
{
"service": "agentbot-clone",
"version": "0.1.0",
"protocol": "x402-tempo",
"clonePrice": "1.0 pathUSD",
"chainId": 4217
}
| Field | Type | Description |
|---|
service | string | Service identifier |
version | string | Clone service version |
protocol | string | Payment protocol used |
clonePrice | string | Current price to clone an agent |
chainId | number | Blockchain chain ID for payments |
List provisioned agents
GET /api/agents/provision
Requires session authentication.
Response
{
"success": true,
"agents": [
{
"id": "agent_789",
"name": "My Agent",
"model": "claude-opus-4-6",
"status": "running",
"websocketUrl": "ws://openclaw-gateway:10000/agent/user_123",
"createdAt": "2026-03-19T00:00:00Z",
"updatedAt": "2026-03-19T00:00:00Z"
}
],
"count": 1
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 500 | Failed to list agents |
Get agent configuration
GET /api/agents/:id/config
Returns the current configuration for an agent. Requires authentication and ownership.
Response
{
"config": {},
"status": "ok"
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 404 | Agent not found or agent configuration not found |
| 500 | Failed to fetch agent configuration |
Update agent configuration
PUT /api/agents/:id/config
Updates the configuration for an agent. Requires authentication and ownership. The request body is forwarded to the backend.
Response
{
"config": {},
"status": "updated"
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 404 | Agent not found |
| 500 | Failed to update agent configuration |
Get agent logs
Returns logs for an agent. Requires authentication and ownership.
This endpoint currently returns mock data. Log entries are generated placeholders, not real agent logs. For real-time logs, use the
live log stream endpoint instead.
Query parameters
| Parameter | Type | Description |
|---|
limit | number | Maximum log entries to return (default: 50, max: 100) |
level | string | Filter by log level (for example, info, error, warn) |
Response
{
"logs": [
{
"id": "log_1",
"timestamp": "2026-03-19T00:00:00Z",
"level": "info",
"message": "Agent activity log entry 1",
"source": "agent",
"agentId": "agent_123"
}
],
"total": 50,
"limit": 50,
"status": "ok"
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 404 | Agent not found |
| 500 | Failed to fetch logs |
Stream agent logs
The live log streaming endpoints (
/api/logs/:agentId/stream,
/api/logs/:agentId/history,
POST /api/logs/:agentId/stop, and
GET /api/logs/active) are planned for a future release. See the
live log tail page for the intended specification.
Get agent messages
GET /api/agents/:id/messages
Returns paginated messages for an agent. Requires authentication and ownership.
Query parameters
| Parameter | Type | Description |
|---|
limit | number | Maximum messages to return (default: 50, max: 100) |
offset | number | Offset for pagination (default: 0) |
Response
{
"messages": [
{
"id": "msg_1",
"agentId": "agent_123",
"sender": "user",
"content": "Hello",
"timestamp": "2026-03-19T00:00:00Z",
"platform": "telegram"
}
],
"total": 0,
"limit": 50,
"offset": 0,
"status": "ok"
}
This endpoint currently returns mock data. Message entries are generated placeholders. A future release will connect this endpoint to the backend message store.
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 404 | Agent not found |
| 500 | Failed to fetch messages |
Get agent stats
GET /api/agents/:id/stats
Returns live container metrics when available, with a mock fallback.
Response (live)
{
"stats": {
"agentId": "agent_123",
"cpu": "0.15%",
"memory": "128MiB / 2GiB",
"memoryPercent": "6.25%",
"network": "1.2kB / 3.4kB",
"uptime": 86400000,
"uptimeFormatted": "1d 0h",
"status": "running",
"pids": "12",
"messagesProcessed": "N/A",
"messagesPerHour": "N/A",
"averageResponseTime": "N/A",
"successRate": "N/A",
"errorRate": "N/A"
},
"status": "ok"
}
Response (mock fallback)
When the backend is unavailable, mock data is returned with "status": "mock":
{
"stats": {
"agentId": "agent_123",
"messagesProcessed": 1234,
"messagesPerHour": 456,
"averageResponseTime": 789,
"uptime": 12345,
"successRate": "95.42",
"errorRate": "4.58",
"timestamp": "2026-03-19T00:00:00Z"
},
"status": "mock"
}
Agent lifecycle
Lifecycle operations are available at two endpoint patterns depending on which service you call:
- Web proxy:
/api/instance/:userId/{action} — requires session authentication and proxies to the backend.
- Backend direct:
/api/agents/:id/{action} — requires API key authentication.
Both patterns support the same actions. The examples below use the backend pattern.
All lifecycle operations require Docker to be available on the backend server. When Docker is unavailable, these endpoints return
500 with an error message describing the failure. You can check Docker availability using the
backend health endpoint — when the
docker field is
unavailable, lifecycle operations will fail. The API itself continues to serve non-Docker endpoints normally.
Start agent
POST /api/agents/:id/start
{
"success": true,
"status": "active"
}
Stop agent
POST /api/agents/:id/stop
{
"success": true,
"status": "stopped"
}
Restart agent
POST /api/agents/:id/restart
{
"success": true,
"status": "active",
"healedLegacyModel": false,
"healMessage": "",
"openclawVersion": "2026.3.13"
}
| Field | Type | Description |
|---|
healedLegacyModel | boolean | Whether a deprecated model was automatically migrated during restart |
healMessage | string | Description of the migration performed (empty if none) |
openclawVersion | string | Current OpenClaw runtime version |
Update agent image
POST /api/agents/:id/update
Triggers an image update on the backend. Before replacing the container, the endpoint creates a compressed backup of the agent’s data volume. If the new image fails to start, the endpoint automatically rolls back to the previous image.
Request body
| Field | Type | Required | Description |
|---|
image | string | No | Custom container image to deploy. When omitted, the platform default image is used. |
Response
{
"success": true,
"status": "active",
"image": "ghcr.io/openclaw/openclaw:2026.3.13",
"previousImage": "ghcr.io/openclaw/openclaw:2026.3.12",
"backupPath": "/backups/agent_123_2026-03-20",
"openclawVersion": "2026.3.13"
}
| Field | Type | Description |
|---|
image | string | New container image. The platform default is ghcr.io/openclaw/openclaw:2026.3.13. |
previousImage | string | Previous container image before the update |
backupPath | string | null | Path to the pre-update backup archive |
openclawVersion | string | Current OpenClaw runtime version |
When the new container fails to start, the endpoint removes the failed container and recreates it using previousImage. The caller still receives a 500 error, but the agent is restored to its prior working state. The pre-update backup remains available at backupPath for manual recovery if needed.
Errors
| Code | Description |
|---|
| 400 | Invalid Docker image name |
| 500 | Update failed. When automatic rollback succeeds, the agent continues running on the previous image. |
Repair agent
POST /api/agents/:id/repair
Returns the backend response directly.
{
"success": true,
"message": "Agent repaired successfully"
}
Reset agent memory
POST /api/agents/:id/reset-memory
Returns the backend response directly.
{
"success": true,
"message": "Memory reset successfully"
}
Lifecycle error responses
Backend lifecycle endpoints return the following shape on failure:
{
"error": "Error message describing the failure"
}
Web proxy lifecycle endpoints return a different error shape:
{
"success": false,
"status": "error"
}
| Code | Source | Description |
|---|
| 401 | Both | Unauthorized — missing or invalid authentication |
| 403 | Web proxy | Forbidden — authenticated user does not own this agent instance |
| 500 | Backend | Internal server error (for example, Docker unavailable or container operation failed) |
| 502 | Web proxy | Backend service unavailable |
Get instance details
GET /api/instance/:userId
Returns the current status and metadata for an agent instance.
Response
{
"userId": "user_123",
"status": "running",
"startedAt": "2026-03-01T00:00:00Z",
"subdomain": "user_123.agents.localhost",
"url": "https://user_123.agents.localhost",
"plan": "solo",
"openclawVersion": "2026.2.17"
}
Get instance stats
GET /api/instance/:userId/stats
Returns resource usage statistics for an agent instance.
Response
{
"userId": "user_123",
"cpu": "0.15%",
"memory": "128MiB",
"status": "running",
"plan": "solo",
"openclawVersion": "2026.3.13"
}
Get agent gateway token
GET /api/agents/:id/token
Returns the gateway token for the agent. If no token exists, a new cryptographically random token is generated using 32 bytes of entropy (returned as a 64-character hex string). Tokens generated by the container entrypoint (when the OPENCLAW_GATEWAY_TOKEN environment variable is not set) use 16 bytes (32 hex characters).
{
"token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
}
Errors
| Code | Description |
|---|
| 404 | Agent not found |
| 500 | Failed to get token |
Agent verification
Agents can be verified using multiple verification types: eas (Ethereum Attestation Service), coinbase, ens, or webauthn.
Get verification status
GET /api/agents/:id/verify
On the backend, the GET endpoint uses /api/agents/:id/verification while POST and DELETE use /api/agents/:id/verify. The web API uses /api/agents/:id/verify for all three methods (GET, POST, DELETE).
{
"verified": false,
"verificationType": null,
"attestationUid": null,
"verifierAddress": null,
"verifiedAt": null,
"metadata": null
}
Verify agent
POST /api/agents/:id/verify
Request body
Requires Content-Type: application/json header.
| Field | Type | Required | Description |
|---|
verificationType | string | Yes | One of: eas, coinbase, ens, webauthn |
attestationUid | string | No | Attestation UID from EAS |
walletAddress | string | No | Address of the verifying wallet (web API) |
signature | string | No | Wallet signature for verification (web API) |
The web API always sets verified: true on success. The backend accepts an additional verified boolean, verifierAddress, and metadata object directly.
Response
{
"success": true,
"verified": true,
"verificationType": "eas",
"attestationUid": "0x123...",
"verifiedAt": "2026-03-19T00:00:00Z"
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized (handled by authentication middleware) |
| 404 | Agent not found |
| 500 | Failed to update verification |
Remove verification
DELETE /api/agents/:id/verify
Provision with channel tokens
Provisions a new agent with messaging channel tokens. Requires bearer token (API key) authentication. When a session is active, the user’s email is automatically resolved from it. At least one channel token is required.
This endpoint is subject to the general rate limit of 120 requests per minute per IP.
The request is proxied to the backend provisioning service. When MUX_TOKEN_ID and MUX_TOKEN_SECRET are configured, the backend creates a real Mux live stream via the Mux API with public playback policy. When Mux credentials are not configured, placeholder streaming credentials are returned instead.
Request body
| Field | Type | Required | Description |
|---|
telegramToken | string | Conditional | Telegram bot token. At least one channel token is required. |
telegramUserId | string | No | Telegram user ID for owner binding |
whatsappToken | string | Conditional | WhatsApp API token. At least one channel token is required. |
discordBotToken | string | Conditional | Discord bot token. At least one channel token is required. |
aiProvider | string | No | AI provider (default: openrouter). Options: openrouter, gemini, groq, anthropic, openai. Each provider maps to a default model — see AI provider defaults below. |
apiKey | string | No | API key for the AI provider |
plan | string | No | Plan tier. Options: solo, collective, label, network. Defaults to free when omitted, which is not a valid plan and returns 400 with the message Invalid plan. A paid plan must be specified explicitly. |
email | string | No | User email address. When omitted, the email is automatically populated from the authenticated session if one exists. The resolved email is forwarded to the backend in the X-User-Email header. |
stripeSubscriptionId | string | No | Stripe subscription ID from checkout |
When a session is active, the server resolves the user email from the session via getServerSession. If the email field is also present in the request body, the request body value takes precedence. The resolved email is sent to the backend provisioning service in the X-User-Email header.
The following request fields are deprecated and no longer accepted: whatsappPhoneNumberId, whatsappBusinessAccountId, discordGuildId, discordChannelId.
Response
The proxy returns a filtered subset of the backend response:
{
"success": true,
"userId": "a1b2c3d4e5",
"subdomain": "dj-a1b2c3d4e5.agentbot.raveculture.xyz",
"url": "https://dj-a1b2c3d4e5.agentbot.raveculture.xyz",
"streamKey": "sk-ab12-cd34-ef56",
"liveStreamId": "x7k9m2p4q1"
}
The /api/provision proxy returns only success, userId, subdomain, url, streamKey, and liveStreamId. The full response shape from the backend provisioning service is shown below.
Full backend response
When calling the backend provisioning service directly, the response includes additional fields.
Channel tokens (telegramToken, discordBotToken, whatsappToken) are no longer included in the provision response. Tokens are write-only secrets — they are stored server-side but never returned to the caller.
{
"success": true,
"userId": "a1b2c3d4e5",
"agentId": "a1b2c3d4e5",
"id": "a1b2c3d4e5",
"aiProvider": "openrouter",
"aiProviderConfig": {
"model": "openai/gpt-4o-mini",
"baseUrl": "https://openrouter.ai/api/v1",
"requiresKey": true
},
"plan": "solo",
"streamKey": "sk-ab12-cd34-ef56",
"liveStreamId": "x7k9m2p4q1",
"rtmpServer": "rtmps://live.mux.com/app",
"playbackUrl": "https://image.mux.com/x7k9m2p4q1/playlist.m3u8",
"subdomain": "dj-a1b2c3d4e5.agentbot.raveculture.xyz",
"url": "https://dj-a1b2c3d4e5.agentbot.raveculture.xyz",
"hls": {
"playlistUrl": "https://image.mux.com/x7k9m2p4q1/playlist.m3u8"
},
"rtmp": {
"server": "rtmps://live.mux.com/app",
"key": "sk-ab12-cd34-ef56"
},
"status": "active",
"createdAt": "2026-03-20T00:00:00Z",
"metadata": {
"channels": {
"telegram": "enabled",
"discord": "disabled",
"whatsapp": "disabled"
},
"streaming": {
"provider": "mux",
"lowLatency": true,
"resolution": "1920x1080",
"bitrate": "5000k"
}
},
"container": {
"name": "openclaw-a1b2c3d4e5",
"status": "running",
"port": 19000,
"gatewayUrl": "http://127.0.0.1:19000"
}
}
The
container object is included when the backend successfully creates a Docker container for the agent. If container creation fails (for example, when Docker is unavailable), provisioning still succeeds and the
container field is omitted. The agent can operate using API-side processing until a container becomes available. You can check Docker availability using the
backend health endpoint.
| Field | Type | Description |
|---|
container.name | string | Docker container name |
container.status | string | Container status (for example, running) |
container.port | number | Host port mapped to the container gateway (maps to internal port 18789) |
container.gatewayUrl | string | Local URL for the container gateway |
Each agent container exposes multiple ports. The deployment maps host port container.port to internal port 18789 (gateway) and container.port + 2 to internal port 18791. The official OpenClaw image also exposes port 18790 (bridge) which can be mapped separately if needed.
Errors
| Code | Description |
|---|
| 400 | At least one channel token required (Telegram, WhatsApp, or Discord), or invalid aiProvider value |
| 400 | Invalid plan value. The plan field must be one of solo, collective, label, or network. Unrecognized values (including the default free) return this error. |
| 402 | Active subscription required. Returned when a valid plan is specified but no Stripe subscription ID is provided and the caller is not an admin or tester. The response body includes a code field set to PAYMENT_REQUIRED. |
| 402 | Agent limit reached for your plan. The response body includes a code field set to AGENT_LIMIT_REACHED, along with current (current agent count) and limit (maximum allowed) fields. Limits: solo 1, collective 3, label 10, network unlimited. |
| 500 | Internal server error |
| 502 | Provisioning service unavailable or returned an error. All backend URLs failed or returned non-success responses. |
| 503 | Provisioning is temporarily disabled (kill switch active) |
AI provider defaults
Each aiProvider value maps to a default model and base URL. There are two model configurations: the container config (used by the agent’s internal gateway) and the provision response metadata (aiProviderConfig field). These may differ.
Container config models
These models are configured inside the agent container at provisioning time and are used by the gateway’s model fallback chain:
| Provider | Primary model | Fallback model | Base URL |
|---|
openrouter | xiaomi/mimo-v2-pro | openrouter/anthropic/claude-sonnet-4, openrouter/google/gemini-2.5-flash | https://openrouter.ai/api/v1 |
gemini | google/gemini-2.0-flash | openrouter/anthropic/claude-sonnet-4-5 | https://generativelanguage.googleapis.com/v1beta/models |
groq | groq/gemma2-9b-it | openai/gpt-4o-mini | https://api.groq.com/openai/v1 |
anthropic | anthropic/claude-sonnet-4-5 | openai/gpt-4o | https://api.anthropic.com/v1 |
openai | openai/gpt-4o | openai/gpt-4o-mini | https://api.openai.com/v1 |
minimax | MiniMax/MiniMax-Text-01 | openai/gpt-4o-mini | https://api.minimax.chat/v1 |
The aiProviderConfig object returned in the provision response uses different default models:
| Provider | Default model | Base URL |
|---|
openrouter | openai/gpt-4o-mini | https://openrouter.ai/api/v1 |
gemini | gemini-2.0-flash | https://generativelanguage.googleapis.com/v1beta/models |
groq | mixtral-8x7b-32768 | https://api.groq.com/openai/v1 |
anthropic | claude-3-sonnet-20240229 | https://api.anthropic.com/v1 |
openai | openai/gpt-4o | https://api.openai.com/v1 |
minimax | MiniMax/MiniMax-Text-01 | https://api.minimax.chat/v1 |
Each provider includes a fallback model in the container config that is used automatically when the primary model is unavailable or returns an error.
minimax is available as a fallback in the provider configuration map but is not currently accepted as a value for the aiProvider request parameter. Passing minimax as aiProvider returns a 400 validation error. This provider may be enabled in a future release.
Channel configuration
When an agent is provisioned, its channel configuration is generated based on the tokens provided. All channels share a set of defaults and each channel type has specific settings.
Channel defaults
| Setting | Value | Description |
|---|
groupPolicy | allowlist | Only explicitly allowed users can interact with the agent in group contexts |
heartbeat.showOk | false | Suppress heartbeat OK messages |
heartbeat.showAlerts | true | Show heartbeat alert messages |
heartbeat.useIndicator | true | Display a status indicator |
Telegram channel settings
| Setting | Value | Description |
|---|
dmPolicy | allowlist or pairing | allowlist when owner IDs are provided, pairing otherwise |
groups.*.requireMention | true | Agent only responds in groups when mentioned |
historyLimit | 50 | Number of messages retained in context |
replyToMode | first | Reply threading mode |
streaming | partial | Enable partial message streaming |
retry.attempts | 3 | Maximum retry attempts |
retry.minDelayMs | 400 | Minimum delay between retries |
retry.maxDelayMs | 30000 | Maximum delay between retries |
retry.jitter | 0.1 | Jitter factor for retry delays |
Discord channel settings
| Setting | Value | Description |
|---|
dmPolicy | allowlist or pairing | allowlist when owner IDs are provided, pairing otherwise |
dm.enabled | true | Accept direct messages |
dm.groupEnabled | false | Group DMs are disabled |
historyLimit | 20 | Number of messages retained in context |
streaming | partial | Enable partial message streaming |
retry.attempts | 3 | Maximum retry attempts |
retry.minDelayMs | 500 | Minimum delay between retries |
retry.maxDelayMs | 30000 | Maximum delay between retries |
retry.jitter | 0.1 | Jitter factor for retry delays |
WhatsApp channel settings
| Setting | Value | Description |
|---|
dmPolicy | allowlist or pairing | allowlist when owner IDs are provided, pairing otherwise |
groups.*.requireMention | true | Agent only responds in groups when mentioned |
sendReadReceipts | true | Send read receipts for incoming messages |
Group chat mention patterns
All channels that support group chat use the following default mention patterns: @agent and agent. The agent only responds in group conversations when one of these patterns is detected in the message.
Each agent is assigned a tool profile at provisioning time based on its plan tier. The tool profile determines which built-in tools the agent can use.
| Plan | Tool profile | Description |
|---|
solo | messaging | Chat-only tools suitable for messaging workflows |
collective | coding | Full development tools including code execution |
label | coding | Full development tools including code execution |
network | coding | Full development tools including code execution |
The tool profile is set once at container creation and persists for the lifetime of the agent. Upgrading your plan does not automatically change the tool profile of existing agents — you need to reprovision the agent or use the
repair endpoint to apply the new profile.
All tool profiles deny browser and canvas tools inside containers. The coding profile includes shell commands (ls, cat, grep, curl, git, node, python3, and others) while the messaging profile restricts the agent to chat-oriented capabilities.
Deploy agent (backend)
This is a backend-only endpoint. It deploys an agent container directly and requires a Content-Type: application/json header. Requires bearer token authentication. Rate limited to 5 requests per minute per IP.
Request body
| Field | Type | Required | Description |
|---|
agentId | string | Yes | Unique agent identifier |
config | object | No | Deployment configuration |
config.telegramToken | string | Yes | Telegram bot token |
config.ownerIds | string[] | No | Telegram owner user IDs |
config.aiProvider | string | No | AI provider (default: openrouter) |
config.apiKey | string | No | API key for the AI provider |
config.plan | string | No | Plan tier. Options: label, solo, collective, network. |
Response (201 Created)
{
"id": "deploy-agent_123",
"agentId": "agent_123",
"subdomain": "agent_123.agents.localhost",
"url": "https://agent_123.agents.localhost",
"status": "active",
"openclawVersion": "2026.3.13"
}
Response (200 Already Active)
If the agent container is already running, returns the existing deployment details with the same shape as the 201 response.
Errors
| Code | Description |
|---|
| 400 | agentId is required, Invalid agentId, or telegramToken is required |
| 401 | Unauthorized |
| 500 | Deployment failed. When Docker is not available on the server, the error message indicates that container provisioning requires Docker. Check the backend health endpoint to verify Docker availability before deploying. |
OpenClaw version (backend)
GET /api/openclaw/version
Returns the current OpenClaw runtime version. Requires bearer token authentication.
Response
{
"openclawVersion": "2026.3.13",
"image": "ghcr.io/openclaw/openclaw:2026.3.13",
"deployedAt": "2026-03-20T00:00:00Z"
}
List instances (backend)
GET /api/openclaw/instances
Returns all running agent instances. Requires bearer token authentication.
Response
{
"instances": [
{
"agentId": "agent_123",
"name": "openclaw-agent_123",
"image": "ghcr.io/openclaw/openclaw:2026.3.13",
"status": "running",
"createdAt": "2026-03-01T00:00:00Z",
"version": "2026.3.13",
"metadata": null
}
],
"count": 1
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |
| 500 | Failed to list instances |
Get instance container stats (backend)
GET /api/openclaw/instances/:id/stats
Returns container resource usage for a specific agent. Requires bearer token authentication.
Path parameters
| Parameter | Type | Description |
|---|
id | string | Agent ID |
Response
{
"agentId": "agent_123",
"cpu": "12.5%",
"memory": "100MiB / 1GiB",
"memoryPercent": "10.0%",
"network": "1.2kB / 3.4kB",
"blockIO": "0B / 0B",
"pids": "12",
"status": "running",
"uptime": 86400000,
"uptimeFormatted": "1d 0h",
"timestamp": "2026-03-20T00:00:00Z"
}
Agent interaction
GET /api/agent
POST /api/agent
Unified endpoint for interacting with agents. All requests require session authentication. The userId is always bound to the authenticated session and cannot be overridden by the client.
GET actions
Pass the action query parameter to select the operation.
List endpoints
Returns available endpoints and version information when no action is specified.
{
"apiVersion": "1.0.0",
"agentbotVersion": "2026.3.1",
"endpoints": {
"GET /api/agent": "List endpoints",
"GET /api/agent?action=health": "Health status",
"GET /api/agent?action=sessions": "List sessions",
"GET /api/agent?action=session&sessionId=xxx": "Get session details",
"GET /api/agent?action=memory": "Get agent memory",
"GET /api/agent?action=skills": "List available skills",
"GET /api/agent?action=credentials": "List configured credentials",
"POST /api/agent": "Send message to agent",
"POST /api/agent?action=create-session": "Create new session",
"POST /api/agent?action=update-skill": "Enable/disable skill"
}
}
Health
GET /api/agent?action=health
{
"status": "running",
"version": "2026.3.1",
"apiVersion": "1.0.0",
"uptime": 86400,
"model": "claude-sonnet-4-20250514",
"channels": ["telegram"],
"skills": [],
"lastSeen": 1710806400000
}
List sessions
GET /api/agent?action=sessions
{
"sessions": [
{
"id": "sess_abc123",
"status": "active",
"messageCount": 5,
"createdAt": 1710806400000,
"lastActivity": 1710810000000
}
]
}
Get session
GET /api/agent?action=session&sessionId=sess_abc123
Returns the full session including messages.
Memory
GET /api/agent?action=memory
Returns the last 10 messages from the active session (truncated to 100 characters each).
{
"memory": [
{ "role": "user", "content": "Hello, can you help me with..." },
{ "role": "assistant", "content": "Of course! Let me..." }
]
}
Skills
GET /api/agent?action=skills
Returns skills available on the agent instance.
Credentials
GET /api/agent?action=credentials
Returns which credentials are configured for the agent.
{
"credentials": {
"anthropic": false,
"openai": false,
"openrouter": true,
"google": false,
"telegram": true,
"discord": false,
"whatsapp": false
}
}
POST actions
Pass the action field in the request body.
Chat
| Field | Type | Required | Description |
|---|
action | string | No | Set to chat or omit (default action) |
message | string | Yes | Message to send to the agent |
sessionId | string | No | Session ID to continue. A new session is created if omitted and no active session exists. |
{
"sessionId": "sess_abc123",
"reply": "Agent is processing your request...",
"timestamp": 1710810000000
}
Create session
| Field | Type | Required | Description |
|---|
action | string | Yes | create-session |
{
"sessionId": "sess_abc123",
"status": "active"
}
Update skill
| Field | Type | Required | Description |
|---|
action | string | Yes | update-skill |
skillId | string | Yes | Skill ID to enable or disable |
enabled | boolean | No | Whether to enable or disable the skill. Defaults to false (removes the skill) when omitted. |
{
"success": true,
"skillId": "browser",
"enabled": true
}
Set credential
| Field | Type | Required | Description |
|---|
action | string | Yes | set-credential |
key | string | Yes | Credential key (for example, anthropic, telegram) |
value | string | No | Credential value. When omitted, the credential is marked as unconfigured. |
{
"success": true,
"key": "anthropic",
"configured": true
}
Errors
| Code | Description |
|---|
| 400 | Invalid action or missing required fields |
| 401 | Unauthorized |
| 404 | Session not found |
| 500 | Internal error |
Send message
Requires session authentication.
Request body
| Field | Type | Required | Description |
|---|
message | string | Yes | Message to send |
topic | string | No | Conversation topic |
{
"message": "Hello!",
"topic": "general"
}
Response
{
"id": "msg_123",
"message": "Hello!",
"topic": "general",
"status": "sent",
"timestamp": "2026-03-19T00:00:00Z",
"reply": "Message received by agent"
}
Errors
| Code | Description |
|---|
| 400 | Message required |
| 401 | Unauthorized |
| 500 | Failed to send message |
List messages
Returns the message history. Requires session authentication.
Response
{
"messages": [],
"count": 0
}
Errors
| Code | Description |
|---|
| 401 | Unauthorized |