Skip to main content

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

GET /api/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"
  }
]
FieldTypeDescription
[].idstringAgent identifier
[].statusstringCurrent agent status
[].createdstringISO 8601 creation timestamp
[].subdomainstringAgent subdomain
[].urlstringAgent 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"
}
FieldTypeDescription
agentsarrayList of agent objects owned by the authenticated user
agents[].idstringAgent identifier
agents[].namestringAgent name
agents[].modelstringAI model assigned to the agent
agents[].statusstringCurrent agent status
agents[].websocketUrlstringWebSocket URL for the agent gateway
agents[].createdAtstringISO 8601 creation timestamp
agents[].updatedAtstringISO 8601 last update timestamp
countnumberTotal number of agents returned
statusstringResponse 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

POST /api/agents
Creates a new agent with an auto-generated ID and stores its metadata on disk. Requires bearer token authentication (backend).

Request body

FieldTypeRequiredDescription
namestringYesAgent name
configobjectNoAgent configuration
config.planstringNoPlan tier (for example, solo, collective, label, network). Defaults to free when omitted. Note that free is not a standard plan tier and may not be recognized by other endpoints.
config.aiProviderstringNoAI 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

CodeDescription
400Name required
401Unauthorized
500Failed to create agent
For provisioning an agent with messaging channel tokens and a live Railway service deployment, use POST /api/agents/provision or POST /api/provision instead.

Get agent

GET /api/agents/:id
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.28",
  "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.28",
    "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 set to "ok".

Errors

CodeDescription
401Unauthorized
404Agent not found or not owned by user
500Failed to fetch agent

Rename agent

PATCH /api/agents/:id
Renames an agent. Requires session authentication and ownership of the agent. The name is updated in the database immediately. The endpoint also makes a best-effort attempt to sync the new name to the backend — if the backend is unreachable, the rename still succeeds (the database is the source of truth for agent names).

Request body

FieldTypeRequiredDescription
namestringYesNew agent name. Must be between 1 and 64 characters after trimming whitespace.

Response

{
  "success": true,
  "agent": {
    "id": "agent_123",
    "name": "New Agent Name",
    "status": "running",
    "updatedAt": "2026-03-27T12:00:00Z"
  }
}
FieldTypeDescription
successbooleanWhether the rename succeeded
agent.idstringAgent identifier
agent.namestringUpdated agent name
agent.statusstringCurrent agent status
agent.updatedAtstringISO 8601 timestamp of the update

Errors

CodeDescription
400Name is required (empty or whitespace-only string)
400Name too long (max 64 chars)
401Unauthorized
404Agent not found or not owned by user
500Failed to rename agent

Update agent

PUT /api/agents/:id
Updates an agent’s metadata including plan, AI provider, and configuration. Requires bearer token authentication (backend).

Request body

FieldTypeRequiredDescription
planstringNoPlan tier
aiProviderstringNoAI provider
configobjectNoAdditional configuration

Response

{
  "id": "agent_123",
  "plan": "collective",
  "aiProvider": "anthropic",
  "subdomain": "agent_123.agents.localhost",
  "status": "active",
  "message": "Agent updated"
}

Errors

CodeDescription
401Unauthorized
404Agent not found
500Failed to update agent
To update agent configuration through the web proxy with session authentication, use PUT /api/agents/:id/config instead.

Delete agent

DELETE /api/agents/:id
Stops and removes the agent’s local Docker container, deallocates its port, and removes its metadata file. Requires bearer token authentication (backend).

Response

{
  "id": "agent_123",
  "deleted": true
}

Errors

CodeDescription
401Unauthorized
500Failed to delete agent
The backend uses best-effort cleanup (service destruction and 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.
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 as a Railway service. 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

FieldTypeRequiredDescription
namestringYesAgent name. Must be between 1 and 64 characters after trimming whitespace.
modelstringNoAI model (default: claude-opus-4-6). Options: claude-opus-4-6, gpt-4, custom
configobjectNoAgent configuration
tierstringNoSubscription 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 provisioning route (POST /api/provision) enforces its own limits (solo: 1, collective: 3, label: 10, network: unlimited). These provisioning limits determine how many agents you can create. The plan middleware enforces separate per-request limits for AI model access and skill usage. The limit cannot be overridden in the request body.
The backend also accepts legacy plan aliases for resource allocation: underground (2 GB / 1 CPU), starter (2 GB / 1 CPU), pro (4 GB / 2 CPU), scale (8 GB / 4 CPU), enterprise (16 GB / 4 CPU), and white_glove (32 GB / 8 CPU). These are accepted in addition to the standard plan names (solo, collective, label, network) when determining container resource limits.

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.
Admin status is determined by checking the session email against ADMIN_EMAILS. This endpoint does not accept an email field in the request body — only the authenticated session email is used for the admin check. The POST /api/provision endpoint uses the same session-only admin check (see admin check).
The backend also supports a TESTER_EMAILS environment variable. When backend payment enforcement is re-enabled, emails listed in TESTER_EMAILS will bypass the Stripe subscription check, similar to admin emails. This feature is currently inactive because backend payment enforcement is disabled (see the 402 error note below).

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

CodeDescription
400Agent name is required
401Unauthorized
402Active subscription required to provision agents
429Agent 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.
500Failed to provision agent

Clone agent

POST /api/agents/clone
Not yet available. Agent cloning is under development and this endpoint currently returns 501 Not Implemented. No payment is processed. The request body is ignored.

Response (501 Not Implemented)

{
  "error": "Agent cloning is not yet available",
  "message": "This feature is under development. No payment has been charged.",
  "status": "unavailable"
}
All POST requests to this endpoint return 501 regardless of the request body. No payment flow is initiated.

Errors

CodeDescription
501Agent cloning is not yet available

Clone service health

GET /api/agents/clone
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
}
FieldTypeDescription
servicestringService identifier
versionstringClone service version
protocolstringPayment protocol used
clonePricestringCurrent price to clone an agent
chainIdnumberBlockchain chain ID for payments

Preflight checks (deprecated)

This endpoint has been deprecated and is no longer available. Requests to this endpoint will return a 404 error.
GET /api/agents/preflight?action={action}&agentId={agentId}
Validates all requirements before performing an operation on an agent. Returns a step-by-step checklist with the status of each prerequisite and the next recommended action.

Query parameters

ParameterTypeRequiredDescription
agentIdstringYesAgent identifier to run preflight checks against
actionstringNoThe operation to validate prerequisites for. Defaults to setup. Options: setup, sponsorship, token, full.

Response

This endpoint no longer returns a response. The previous response included checks, pipeline, and nextAction fields.

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

CodeDescription
401Unauthorized
500Failed 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

CodeDescription
401Unauthorized
404Agent not found or agent configuration not found
500Failed 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

CodeDescription
401Unauthorized
404Agent not found
500Failed to update agent configuration

Get agent logs

GET /api/agents/:id/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

ParameterTypeDescription
limitnumberMaximum log entries to return (default: 50, max: 100)
levelstringFilter 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

CodeDescription
401Unauthorized
404Agent not found
500Failed 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

ParameterTypeDescription
limitnumberMaximum messages to return (default: 50, max: 100)
offsetnumberOffset 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

CodeDescription
401Unauthorized
404Agent not found
500Failed to fetch messages

Get agent stats

GET /api/agents/:id/stats
Returns live service 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.
The backend agents route uses local Docker commands (docker start, docker stop, docker restart) for lifecycle operations, not the Railway API. The Railway API is used by the provisioning route (POST /api/provision) for creating new agent services. When Docker is unavailable on the backend host, lifecycle operations return 500 with an error message. You can check availability using the backend health endpoint — when the docker field is unavailable, lifecycle operations will fail.

Start agent

POST /api/agents/:id/start
Restarts (redeploys) a stopped agent service.
{
  "success": true,
  "status": "active"
}

Stop agent

POST /api/agents/:id/stop
Stops the agent service. The service retains its data and configuration and can be resumed with the start endpoint.
{
  "success": true,
  "status": "stopped"
}

Restart agent

POST /api/agents/:id/restart
{
  "success": true,
  "status": "active",
  "healedLegacyModel": false,
  "healMessage": "skip",
  "openclawVersion": "2026.3.28"
}
FieldTypeDescription
healedLegacyModelbooleanWhether a deprecated model was automatically migrated during restart
healMessagestringDescription of the migration performed (skip when no migration was needed, or skip:container-not-running when the container is unavailable)
openclawVersionstringCurrent OpenClaw runtime version

Update agent image

POST /api/agents/:id/update
Triggers an image update on the backend. Before replacing the service, the endpoint creates a backup of the agent’s data. If the new image fails to start, the endpoint automatically rolls back to the previous image.

Request body

FieldTypeRequiredDescription
imagestringNoCustom image to deploy. When omitted, the platform default image is used.

Response

{
  "success": true,
  "status": "active",
  "image": "ghcr.io/openclaw/openclaw:2026.3.28",
  "previousImage": "ghcr.io/openclaw/openclaw:2026.3.12",
  "backupPath": "/opt/agentbot/data/backups/openclaw-updates/agent_123/20260320-000000.tar.gz",
  "openclawVersion": "2026.3.28"
}
FieldTypeDescription
imagestringNew service image. The platform default is ghcr.io/openclaw/openclaw:2026.3.28.
previousImagestringPrevious service image before the update
backupPathstring | nullPath to the pre-update backup archive
openclawVersionstringCurrent OpenClaw runtime version
When the new service fails to start, the endpoint reverts to 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

CodeDescription
400Invalid docker image value
500Update 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"
}
CodeSourceDescription
401BothUnauthorized — missing or invalid authentication
403Web proxyForbidden — authenticated user does not own this agent instance
500BackendInternal server error (for example, Railway API unavailable or service operation failed)
502Web proxyBackend 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": "agentbot-agent-user_123-production.up.railway.app",
  "url": "https://agentbot-agent-user_123-production.up.railway.app",
  "plan": "solo",
  "openclawVersion": "2026.3.24"
}

Get instance stats

GET /api/instance/:userId/stats
Returns resource usage statistics for an agent instance. Requires session authentication and ownership of the instance. The endpoint uses a two-tier fallback strategy:
  1. Backend API — queries the backend service for full resource metrics (CPU, memory, plan, version).
  2. Agent health probe — when the backend is unavailable (for example, returns 503 when suspended), the endpoint probes the agent’s own /healthz and /readyz endpoints directly on Railway. This returns health status instead of full resource metrics.
If both the backend and the agent are unreachable, the endpoint returns a minimal response indicating the stats service is unavailable.

Response (backend available)

When the backend API responds successfully, the full resource metrics are returned:
{
  "userId": "user_123",
  "cpu": "0.15%",
  "memory": "128MiB",
  "status": "running",
  "plan": "solo",
  "openclawVersion": "2026.3.28",
  "health": "healthy",
  "uptime": 86400,
  "messages": 1234,
  "errors": 5
}
FieldTypeDescription
userIdstringAgent instance identifier
cpustringCPU usage. Falls back to "unknown" when not reported by the backend.
memorystringMemory usage. Falls back to "unknown" when not reported by the backend.
statusstringAgent status (for example, running, stopped). Falls back to "unknown".
planstringSubscription plan tier. Falls back to "free".
openclawVersionstringOpenClaw runtime version
healthstringAgent health status. Falls back to "unknown" when not reported.
uptimenumber | undefinedAgent uptime in seconds, when available
messagesnumber | undefinedMessage count, when available
errorsnumber | undefinedError count, when available

Response (backend unavailable, agent healthy)

When the backend is down but the agent’s Railway service is reachable, the endpoint probes the agent’s /healthz endpoint. If /healthz reports the agent is live, the endpoint also probes /readyz to determine readiness.
{
  "userId": "user_123",
  "status": "running",
  "health": "healthy",
  "cpu": "—",
  "memory": "—",
  "uptime": "active",
  "openclawVersion": "2026.3.24"
}
FieldTypeDescription
statusstringrunning when /healthz reports the agent is live, unreachable otherwise
healthstringhealthy when both /healthz and /readyz succeed, degraded when /healthz succeeds but /readyz fails, unreachable when /healthz fails
cpustring"—" when the agent is healthy (resource metrics are not available without the backend), "0%" when unreachable
memorystring"—" when the agent is healthy, "0MB" when unreachable
uptimestring"active" when the agent is healthy, "unknown" when unreachable
openclawVersionstringOpenClaw runtime version (static fallback value)
When the backend is unavailable, CPU and memory metrics cannot be retrieved because the agent’s /healthz and /readyz endpoints do not report resource usage. The cpu and memory fields return "—" to indicate that the agent is running but detailed metrics are unavailable.

Response (both unreachable)

When both the backend and the agent’s Railway service are unreachable:
{
  "userId": "user_123",
  "cpu": "0%",
  "memory": "0MB",
  "status": "unknown",
  "health": "unreachable",
  "error": "Stats service unavailable"
}
FieldTypeDescription
statusstringAlways unknown when both services are unreachable
healthstringAlways unreachable when both services are unreachable
errorstringError message indicating the stats service is unavailable

Errors

CodeDescription
403Forbidden — authenticated user does not own this agent instance

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 service entrypoint (when the OPENCLAW_GATEWAY_TOKEN environment variable is not set) use 24 bytes (48 hex characters).
{
  "token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
}

Errors

CodeDescription
404Agent not found
500Failed 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/verification
The backend GET endpoint uses /api/agents/:id/verification while POST and DELETE use /api/agents/:id/verify. The web API proxies all three methods through /api/agents/:id/verify.
{
  "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.
FieldTypeRequiredDescription
verificationTypestringYesOne of: eas, coinbase, ens, webauthn
attestationUidstringConditionalAttestation UID from EAS. Required when verificationType is eas.
walletAddressstringConditionalAddress of the verifying wallet. Required when verificationType is ens. Optional for coinbase.
signaturestringConditionalCryptographic signature or attestation data. Required when verificationType is coinbase, ens, or webauthn.
The web API always sets verified: true on success and computes the verifierAddress and metadata fields internally based on the verification type. When calling the backend directly, you can pass verified, verifierAddress, and metadata explicitly.
Each verification type requires a different combination of fields:
TypeRequired fields
easattestationUid
coinbasesignature
enssignature, walletAddress
webauthnsignature

Response

{
  "success": true,
  "verified": true,
  "verificationType": "eas",
  "attestationUid": "0x123...",
  "verifiedAt": "2026-03-19T00:00:00Z"
}

Errors

CodeDescription
400Invalid verification type. Must be one of: eas, coinbase, ens, webauthn.
400Missing required field for the selected verification type (for example, Attestation UID required for EAS verification, Signature required for Coinbase verification, Signature and wallet address required for ENS verification, Attestation required for WebAuthn verification)
401Unauthorized (handled by authentication middleware)
404Agent not found
500Failed to update verification

Remove verification

DELETE /api/agents/:id/verify
{
  "success": true
}

Provision with channel tokens

POST /api/provision
Provisions a new agent with messaging channel tokens. Requires session authentication. When a session is active, the user’s email is automatically resolved from it. When autoProvision is true or agentType is business, channel tokens are not required and the agent is provisioned as an OpenClaw-only deployment. Otherwise, at least one channel token (Telegram, WhatsApp, or Discord) is required.

Admin check

Admin status is determined using the session email only. The email field in the request body is not used for admin resolution.
  1. Session email — the email from the authenticated session is checked against the configured ADMIN_EMAILS.
If the session email matches an admin email, the caller is treated as an admin. When the session is missing but the session email resolves to an admin, a synthetic session is created and the request proceeds. Non-admin users without a valid session receive a 401 error.
The body email field is no longer used as a fallback for admin detection. Only the session email is checked. This is a change from previous behavior where the body email was checked when no session email was available.
This endpoint is subject to the general rate limit of 120 requests per minute per IP.

Provisioning strategy

The endpoint provisions agents using a two-path strategy, tried in order:
  1. Backend service — the request is forwarded to the backend Express service (BACKEND_API_URL). If a fallback URL is configured (BACKEND_API_FALLBACK_URL), it is tried next if the primary fails. Non-JSON responses (such as HTML error pages from a proxy or load balancer) are detected and treated as failures, avoiding the previous “Unexpected token” parsing errors.
  2. Railway direct provisioning — when all backend URLs fail or are not configured, the endpoint falls back to provisioning the agent container directly via the Railway GraphQL API. This path requires RAILWAY_API_KEY, RAILWAY_PROJECT_ID, and RAILWAY_ENVIRONMENT_ID to be set. The Railway path creates a new Railway service, injects environment variables (including OPENCLAW_GATEWAY_PORT=18789), sets a start command via the ServiceInstanceUpdate mutation that configures the gateway (local mode, disabled device auth, enabled chat completions endpoint), generates a public domain via the serviceDomainCreate mutation with targetPort: 18789 so that Railway’s HTTP proxy routes traffic directly to the gateway port, and then triggers a deployment. The domain is generated before the deploy so that the service has a routable public URL immediately. The returned URL is the direct Railway domain for the service. The controlUiUrl is constructed with gatewayUrl and token query parameters so the Control UI auto-connects without requiring manual configuration.
If both paths fail, the endpoint returns a 502 error. When the backend path succeeds and 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. The Railway direct path does not create Mux streams.

Request body

FieldTypeRequiredDescription
telegramTokenstringConditionalTelegram bot token. At least one channel token is required unless autoProvision is true or agentType is business.
telegramUserIdstringNoTelegram user ID for owner binding
whatsappTokenstringConditionalWhatsApp API token. At least one channel token is required unless autoProvision is true or agentType is business.
discordBotTokenstringConditionalDiscord bot token. At least one channel token is required unless autoProvision is true or agentType is business.
aiProviderstringNoAI provider (default: openrouter). Options: openrouter, gemini, groq, anthropic, openai. Each provider maps to a default model — see AI provider defaults below.
planstringNoPlan tier. Options: solo, collective, label, network. Defaults to free when omitted. Since free is not a valid plan, omitting this field returns a 400 validation error — you must explicitly specify a paid plan when calling the backend directly.
modelstringNoAI model identifier. When omitted, the default model for the selected aiProvider is used (see AI provider defaults).
skillsstring[]NoList of skill identifiers to enable on the agent.
agentTypestringNoAgent type. When set to business, the agent is provisioned as an OpenClaw-only deployment and channel tokens are not required.
autoProvisionbooleanNoWhen true, the agent is provisioned as an OpenClaw-only deployment and channel tokens are not required. The onboard flow sets this automatically in deploy mode.
emailstringNoUser email address. This field is forwarded to the backend in the request payload but is not used for admin detection — only the session email is used for the admin check (see admin check above). The session email is sent to the backend in the X-User-Email header.
stripeSubscriptionIdstringNoStripe subscription ID from checkout. This field is accepted by the backend provisioning service directly. The web proxy does not forward this field — it performs its own subscription check against the database instead.
The server resolves the user email exclusively from the authenticated session. The session email is sent to the backend provisioning service in the X-User-Email header and the session user ID is sent in the X-User-Id header. The email field in the request body is not used for authentication or admin detection.
The following request fields are deprecated and no longer accepted: whatsappPhoneNumberId, whatsappBusinessAccountId, discordGuildId, discordChannelId.

Response

The response shape depends on which provisioning path succeeds.

Backend path response

When the backend Express service handles the request, the proxy returns a filtered subset:
{
  "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 backend path returns success, userId, subdomain, url, streamKey, and liveStreamId. The full response shape from the backend provisioning service is shown below.

Railway direct path response

When the Railway fallback handles the request, the response has a different shape:
{
  "success": true,
  "userId": "a1b2c3d4e5",
  "url": "https://agentbot-agent-a1b2c3d4e5-production.up.railway.app",
  "status": "deploying"
}
FieldTypeDescription
successbooleanWhether the provisioning request was accepted
userIdstringThe generated agent ID
urlstringThe direct Railway domain URL for the agent. This URL is generated by Railway via the serviceDomainCreate API and points directly to the agent’s Railway service rather than routing through a backend proxy. If domain generation fails, the URL falls back to https://agentbot-agent-{agentId}.up.railway.app.
statusstringAlways deploying for the Railway path. The agent service is created and the deployment is triggered, but it may not be ready to receive traffic immediately.
The Railway path does not return subdomain, streamKey, or liveStreamId. These fields are only available when the backend Express service handles the request. The status field is deploying (not active) because the Railway service is created asynchronously. The Railway path creates a service domain with targetPort: 18789 so that Railway’s HTTP proxy routes incoming requests directly to the OpenClaw gateway port. The start command configures the gateway in local mode with device auth disabled and chat completions enabled before launching on port 18789.
On a successful provision through either path, the proxy persists the openclawUrl and openclawInstanceId to the user record in the database. You can retrieve these values later using GET /api/user/openclaw.

Full backend response

When calling the backend provisioning service directly, the response includes additional fields. The backend returns 200 OK on success (not 201 Created).
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": "agentbot-agent-a1b2c3d4e5",
    "status": "deploying",
    "serviceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "renderUrl": "https://agentbot-agent-a1b2c3d4e5.up.railway.app",
    "controlUiUrl": "https://agentbot-agent-a1b2c3d4e5.up.railway.app/?gatewayUrl=wss%3A%2F%2Fagentbot-agent-a1b2c3d4e5.up.railway.app&token=your-gateway-token"
  }
}
The container object is included when the backend successfully creates a container for the agent. If container creation fails, provisioning still succeeds and the container field is omitted. The agent can operate using API-side processing until the container becomes available. You can check backend availability using the backend health endpoint.
The container.status is deploying because the Railway service is created asynchronously. The service transitions to running once the deployment completes. Device pairing (dangerouslyDisableDeviceAuth) is automatically disabled for user containers at provisioning time — each user has an isolated container, so device auth is unnecessary. The gateway is still protected by token authentication (OPENCLAW_GATEWAY_TOKEN). The service domain is created with targetPort: 18789 so that Railway’s HTTP proxy routes traffic directly to the gateway port.
FieldTypeDescription
container.namestringContainer name (format: agentbot-agent-{userId})
container.statusstringContainer status (for example, running, stopped)
container.serviceIdstringRailway service ID for the agent container.
container.renderUrlstringPublic service URL for the agent container (for example, https://agentbot-agent-{userId}.up.railway.app). The field name is retained for backward compatibility but now points to a Railway URL.
container.controlUiUrlstringAuto-connect URL for the OpenClaw Control UI. The gatewayUrl and token are passed as query parameters (for example, https://service.up.railway.app/?gatewayUrl=wss%3A%2F%2Fservice.up.railway.app&token=...). This allows the Control UI to read the WebSocket endpoint and authentication token on load, bypassing the onboarding redirect that previously stripped hash-fragment credentials. Only present when a gateway token is configured.
container.portnumber | nullDeprecated. Previously held the container’s local listening port. Removed in favor of container.renderUrl.
container.gatewayUrlstringDeprecated. Previously held the local gateway URL. Replaced by container.renderUrl, which points to the service URL instead.

Errors

CodeDescription
400At least one channel token required (Telegram, WhatsApp, or Discord) when autoProvision is not true and agentType is not business, or invalid aiProvider value
400Invalid plan value (backend only). The plan field must be one of solo, collective, label, or network. The web proxy defaults to label when forwarding to the backend, so this error is only returned when calling the backend directly with an unrecognized value. Since the plan field defaults to free when omitted, and free is not a valid plan, callers must always specify an explicit paid plan. The error message is: Invalid plan. Supported: solo, collective, label, network.
401Authentication required. Returned when no valid session is present, or the session email does not match a configured admin email. The body email field is not used for authentication.
403Active subscription required (web proxy). Returned when the authenticated user does not have an active subscription and is not an admin. The response body includes success: false and an error message: Active subscription required. Please purchase a plan to deploy.
402No free tier available. Returned when plan is free (the default when omitted). The response body includes code: "PAYMENT_REQUIRED" and the message "No free tier. Choose a paid plan to get started." You must explicitly specify a paid plan (solo, collective, label, or network).
402Active subscription required (backend). Currently disabled. This check is commented out in the backend while payment enforcement is being validated. When re-enabled, it will be returned when a valid paid plan is specified but no Stripe subscription ID is provided and the caller is not an admin or tester. The response body will include a code field set to PAYMENT_REQUIRED.
402Agent 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. Provisioning limits: solo 1, collective 3, label 10, network unlimited.
500Internal server error
502Provisioning service unavailable. All backend URLs failed or returned non-JSON/error responses, and Railway direct provisioning also failed or is not configured. The error message from the last attempted path is included in the response.
503Provisioning is temporarily disabled (kill switch active) or provisioning service misconfigured.

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 service at provisioning time and are used by the gateway’s model fallback chain:
ProviderPrimary modelFallback modelBase URL
openroutermoonshotai/kimi-k2.5openrouter/openai/gpt-4o-minihttps://openrouter.ai/api/v1
gemini (or google)google/gemini-2.0-flashopenrouter/anthropic/claude-sonnet-4-5https://generativelanguage.googleapis.com/v1beta/models
groqgroq/gemma2-9b-itopenai/gpt-4o-minihttps://api.groq.com/openai/v1
anthropicanthropic/claude-sonnet-4-5openai/gpt-4ohttps://api.anthropic.com/v1
openaiopenai/gpt-4oopenai/gpt-4o-minihttps://api.openai.com/v1
minimaxMiniMax/MiniMax-Text-01openai/gpt-4o-minihttps://api.minimax.chat/v1

Provision response metadata models

The aiProviderConfig object returned in the provision response uses different default models:
ProviderDefault modelBase URL
openrouteropenai/gpt-4o-minihttps://openrouter.ai/api/v1
geminigemini-2.0-flashhttps://generativelanguage.googleapis.com/v1beta/models
groqmixtral-8x7b-32768https://api.groq.com/openai/v1
anthropicclaude-3-sonnet-20240229https://api.anthropic.com/v1
openaigpt-4ohttps://api.openai.com/v1
minimaxMiniMax/MiniMax-Text-01https://api.minimax.chat/v1
Each provider includes a fallback model in the service 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

SettingValueDescription
groupPolicyallowlistOnly explicitly allowed users can interact with the agent in group contexts
heartbeat.showOkfalseSuppress heartbeat OK messages
heartbeat.showAlertstrueShow heartbeat alert messages
heartbeat.useIndicatortrueDisplay a status indicator

Telegram channel settings

SettingValueDescription
dmPolicyallowlist or pairingallowlist when owner IDs are provided, pairing otherwise
groups.*.requireMentiontrueAgent only responds in groups when mentioned
historyLimit50Number of messages retained in context
replyToModefirstReply threading mode
streamingpartialEnable partial message streaming
retry.attempts3Maximum retry attempts
retry.minDelayMs400Minimum delay between retries
retry.maxDelayMs30000Maximum delay between retries
retry.jitter0.1Jitter factor for retry delays

Discord channel settings

SettingValueDescription
dmPolicyallowlist or pairingallowlist when owner IDs are provided, pairing otherwise
dm.enabledtrueAccept direct messages
dm.groupEnabledfalseGroup DMs are disabled
historyLimit20Number of messages retained in context
streamingpartialEnable partial message streaming
retry.attempts3Maximum retry attempts
retry.minDelayMs500Minimum delay between retries
retry.maxDelayMs30000Maximum delay between retries
retry.jitter0.1Jitter factor for retry delays

WhatsApp channel settings

SettingValueDescription
dmPolicyallowlist or pairingallowlist when owner IDs are provided, pairing otherwise
groups.*.requireMentiontrueAgent only responds in groups when mentioned
sendReadReceiptstrueSend 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.

Tool profiles

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.
PlanTool profileDescription
solomessagingChat-only tools suitable for messaging workflows
collectivecodingFull development tools including code execution
labelcodingFull development tools including code execution
networkcodingFull development tools including code execution
The tool profile is set once at service 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 agent services. 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)

POST /api/deployments
This is a backend-only endpoint. It deploys an agent as a Railway service and requires a Content-Type: application/json header. Requires bearer token authentication. Rate limited to 5 requests per minute per IP.

Request body

FieldTypeRequiredDescription
agentIdstringYesUnique agent identifier
configobjectNoDeployment configuration
config.telegramTokenstringYesTelegram bot token
config.ownerIdsstring[]NoTelegram owner user IDs
config.aiProviderstringNoAI provider (default: openrouter)
config.apiKeystringNoAPI key for the AI provider
config.planstringNoPlan tier. Options: label, solo, collective, network. When omitted, defaults to free which resolves to starter resource limits (2 GB memory, 1 CPU).

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.28"
}

Response (200 Already Active)

If the agent service is already running, returns the existing deployment details with the same shape as the 201 response.

Errors

CodeDescription
400agentId is required, Invalid agentId, or telegramToken is required
401Unauthorized
500Deployment failed. When the Railway API is not reachable, the error message indicates that provisioning is unavailable. Check the backend health endpoint to verify Railway API availability before deploying.

OpenClaw version (backend)

GET /api/openclaw/version
Returns the current OpenClaw runtime version. Requires bearer token authentication.

Response

{
  "openclawVersion": "2026.3.28",
  "image": "ghcr.io/openclaw/openclaw:2026.3.28",
  "deployedAt": "2026-03-20T00:00:00Z"
}
deployedAt returns the current server time when the request is made, not the actual deployment time of the OpenClaw runtime.

List instances (backend)

GET /api/openclaw/instances
Returns all running agent services. Requires bearer token authentication.

Response

{
  "instances": [
    {
      "agentId": "agent_123",
      "name": "openclaw-agent_123",
      "image": "ghcr.io/openclaw/openclaw:2026.3.28",
      "status": "Up 2 hours",
      "createdAt": "2026-03-20 00:00:00 +0000 UTC",
      "version": "2026.3.28",
      "metadata": {
        "agentId": "agent_123",
        "createdAt": "2026-03-20T00:00:00Z",
        "plan": "solo"
      }
    }
  ],
  "count": 1
}
The metadata object contains the full agent metadata from the on-disk JSON file and may include additional fields beyond those shown (for example, aiProvider, port, subdomain, url, status, and config).

Errors

CodeDescription
401Unauthorized
500Failed to list instances

Get instance service stats (backend)

GET /api/openclaw/instances/:id/stats
Returns resource usage for a specific agent service. Requires bearer token authentication.

Path parameters

ParameterTypeDescription
idstringAgent 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"
}

Proxy to agent instance (backend)

ALL /api/openclaw/proxy/:agentId/*
Transparently forwards HTTP requests to the agent’s internal service address. The proxy strips the /api/openclaw/proxy/:agentId prefix from the request path before forwarding. WebSocket upgrades are also supported and handled at the server level. No additional authentication is required on the proxy itself — the agent’s own token authentication handles access control.

Path parameters

ParameterTypeDescription
agentIdstringAgent ID. Only alphanumeric characters, hyphens, and underscores are allowed; all other characters are stripped.

Errors

CodeDescription
502Agent instance unreachable
The proxy rewrites the request path so that /api/openclaw/proxy/agent_123/some/path forwards to /some/path on the agent’s internal address. If no path follows the agent ID, the request is forwarded to /.

Get user OpenClaw instance

GET /api/user/openclaw
Returns the authenticated user’s OpenClaw URL, instance ID, and gateway token. These values are set during provisioning when autoProvision is true or agentType is business. The gateway token is a platform-level credential used to authenticate with the OpenClaw Control dashboard. Requires session authentication.

Response

{
  "openclawUrl": "https://dj-a1b2c3d4e5.agentbot.raveculture.xyz",
  "openclawInstanceId": "inst_a1b2c3d4e5",
  "gatewayToken": "ogt_abc123..."
}
FieldTypeDescription
openclawUrlstring | nullThe OpenClaw dashboard URL for this user. null when no OpenClaw instance has been provisioned.
openclawInstanceIdstring | nullThe OpenClaw instance identifier. null when no OpenClaw instance has been provisioned.
gatewayTokenstring | nullThe platform-level gateway token for authenticating with the OpenClaw Control dashboard. null when no gateway token is configured.

Fix OpenClaw start command (admin)

Deprecated. This endpoint has been removed and is no longer available. It was a one-time administrative utility.
GET /api/admin/fix-openclaw
Previously updated the OpenClaw service start command on Railway and triggered a redeploy. The updated start command wrote a gateway configuration file with gateway.trustedProxies and gateway.controlUi.allowedOrigins before launching the OpenClaw process.

Query parameters

ParameterTypeRequiredDescription
keystringYesMust match the configured INTERNAL_API_KEY environment variable

Response

This endpoint no longer returns a response. Any request will result in a 404.

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

GET /api/agent
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

POST /api/agent
FieldTypeRequiredDescription
actionstringNoSet to chat or omit (default action)
messagestringYesMessage to send to the agent
sessionIdstringNoSession 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

FieldTypeRequiredDescription
actionstringYescreate-session
{
  "sessionId": "sess_abc123",
  "status": "active"
}

Update skill

FieldTypeRequiredDescription
actionstringYesupdate-skill
skillIdstringYesSkill ID to enable or disable
enabledbooleanNoWhether to enable or disable the skill. Defaults to false (removes the skill) when omitted.
{
  "success": true,
  "skillId": "browser",
  "enabled": true
}

Set credential

FieldTypeRequiredDescription
actionstringYesset-credential
keystringYesCredential key (for example, anthropic, telegram)
valuestringNoCredential value. When omitted, the credential is marked as unconfigured.
{
  "success": true,
  "key": "anthropic",
  "configured": true
}

Errors

CodeDescription
400Invalid action or missing required fields
401Unauthorized
404Session not found
500Internal error

Send message

POST /api/chat
Sends a message to the caller’s deployed agent via the OpenAI-compatible REST API. The server forwards the message to the agent’s gateway using POST /v1/chat/completions with a bearer token. The gateway must have chatCompletions enabled in its configuration. Requires session authentication.

Request body

FieldTypeRequiredDescription
messagestringYesMessage to send
{
  "message": "Hello!"
}
The topic parameter was removed. Conversation context is no longer passed through this endpoint. If you need to route messages to a specific conversation, use the gateway chat proxy which supports a sessionKey parameter.

Response (200)

{
  "id": "msg_1742472000000",
  "message": "Hello!",
  "agent": "my-agent",
  "reply": "Hi there! How can I help you today?",
  "model": "openclaw/default",
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 25,
    "total_tokens": 37
  },
  "timestamp": "2026-03-20T03:33:15.000Z"
}
FieldTypeDescription
idstringMessage identifier. Uses the upstream completion ID when available, otherwise prefixed with msg_.
messagestringThe original message that was sent
agentstringName of the agent that processed the message
replystringThe agent’s response
modelstringModel identifier used by the gateway for the completion
usageobjectToken usage statistics from the upstream completion
usage.prompt_tokensnumberInput tokens consumed
usage.completion_tokensnumberOutput tokens generated
usage.total_tokensnumberTotal tokens used
timestampstringISO 8601 timestamp of when the response was generated

Errors

CodeDescription
400Message required — the message field is missing from the request body
401Unauthorized — no valid session
404User not found — authenticated user does not exist in the database
404No agent deployed — the user does not have a deployed agent
502Gateway returned a 5xx error — the agent’s gateway encountered an internal error
500Failed to send message — an unexpected error occurred
503Gateway not configured — the server does not have a gateway token configured
The server sends an HTTP POST request to the agent’s gateway for each call. Requests time out after 30 seconds. If the gateway is unreachable or the agent does not respond within this window, a 502 or 500 error is returned.

List messages

GET /api/chat
Returns the message history. Requires session authentication.

Response

{
  "messages": [],
  "count": 0
}

Errors

CodeDescription
401Unauthorized