Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agentbot.raveculture.xyz/llms.txt

Use this file to discover all available pages before exploring further.

Gateway

The v1 gateway routes incoming requests to registered plugins. It supports three payment methods — Stripe (existing), MPP (Machine Payments Protocol) via the Tempo blockchain, and session-based billing for low-latency, off-chain per-call payments.

Base URL

POST /api/v1/gateway

Request

Headers

HeaderTypeRequiredDescription
Content-TypestringYesMust be application/json
X-Plugin-IdstringNoPlugin to route the request to. Overrides the plugin field in the body.
X-Payment-MethodstringNoPayment method to use: stripe, mpp, or session. Defaults to stripe.
AuthorizationstringNoFor MPP payments, use Payment <credential>. For session auth, handled via cookies.
X-Session-IdstringNoActive session ID for session-based billing. Required when X-Payment-Method is session.
X-Wallet-AddressstringNoWallet address that owns the session (0x-prefixed). Required when X-Payment-Method is session.
AcceptstringNoSet to text/event-stream for streaming responses (where supported).

Body

{
  "plugin": "agent",
  "messages": [{ "role": "user", "content": "Hello" }]
}
FieldTypeRequiredDescription
pluginstringNoPlugin ID to route to. The X-Plugin-Id header takes priority if both are provided. Defaults to agent.
Additional body fields are forwarded to the target plugin.

Plugins

The gateway routes to the following plugins:
Plugin IDNameDescriptionAuth requiredStreaming
agentAgentAgent orchestrator for multi-step tasksNoYes
generate-textText GenerationLLM text generationNoYes
ttsText-to-SpeechSpeech synthesisNoNo
sttSpeech-to-TextSpeech transcriptionNoNo
agent is the default plugin when no plugin ID is specified.

Authentication

No plugins currently require authentication. The gateway checks whether a plugin has its auth flag enabled — since no built-in plugin sets this flag, all requests are processed without requiring a session, MPP credential, or payment session. If a custom plugin is registered with auth: true, the gateway enforces either a valid session (cookie-based via NextAuth), a verified MPP payment credential, or an active payment session. If you pay with MPP or use session-based billing, cookie-based authentication is not required for auth-enabled plugins.

Payment flow

The gateway supports three payment methods per request:
  1. Stripe — Default. Requires an active subscription or credits. See Stripe integration.
  2. MPP — Crypto-native payments on the Tempo blockchain. See MPP payments.
  3. Session — Off-chain, per-call billing using a pre-funded payment session. See MPP payments — sessions and the wallet sessions API.
The server selects the payment method using the following priority:
  1. X-Payment-Method header (session, mpp, or stripe)
  2. Presence of an Authorization: Payment header (implies mpp)
  3. Default: stripe

MPP 402 challenge

When an MPP request has no valid credential, the gateway returns 402 Payment Required with pricing information for both payment methods:
{
  "error": "payment_required",
  "message": "Payment required for agent. Choose payment method: Stripe or Tempo MPP.",
  "mpp": {
    "scheme": "Payment",
    "amount": "0.05",
    "currency": "0x20c0000000000000000000000000000000000000",
    "recipient": "0xd8fd0e1dce89beaab924ac68098ddb17613db56f",
    "description": "Agent orchestrator request",
    "nonce": "a1b2c3d4e5f6...",
    "expiresAt": 1742472000000
  },
  "stripe": {
    "checkoutUrl": "/api/v1/payments/stripe/create?plugin=agent",
    "amount": "0.05",
    "currency": "usd"
  }
}
The WWW-Authenticate header is also set:
Payment amount="0.05", currency="0x20c0000000000000000000000000000000000000", recipient="0xd8fd0e1dce89beaab924ac68098ddb17613db56f"

Session-based billing

When X-Payment-Method is session, the gateway auto-debits the caller’s payment session using an off-chain voucher. This avoids the 402 challenge/response round-trip and settles each call in sub-100ms. To use session-based billing:
  1. Open a payment session via POST /api/wallet/sessions. See wallet sessions.
  2. Include X-Session-Id and X-Wallet-Address headers on every gateway request.
  3. The gateway looks up the session, verifies the balance covers the plugin price, and debits the session automatically.
  4. The response includes a Payment-Receipt header with the voucher reference and an X-Session-Remaining header with the updated balance.
If the session is missing, expired, or has insufficient balance, the gateway returns 402 with a descriptive error. See error responses for the full list of session-related error codes.

Response

Success

The gateway forwards the request body to the matched plugin’s upstream URL and returns the plugin’s response directly. The HTTP status code and Content-Type header are preserved from the upstream response.
The gateway no longer returns a synthetic response with plugin, message, timestamp, and payment fields. Responses are now proxied directly from the upstream plugin service. The response shape depends entirely on the plugin being called. Requests have a 30-second timeout.
When paid via MPP, the response includes a Payment-Receipt header with the transaction hash. When paid via a session, the Payment-Receipt header contains the voucher reference (formatted as session:<sessionId>:<nonce>).

Response headers

HeaderDescription
x-plugin-idThe plugin that handled the request
Payment-ReceiptPayment receipt. For MPP: transaction hash. For sessions: voucher reference (session:<sessionId>:<nonce>). Only present for MPP or session-paid requests.
X-Session-RemainingRemaining session balance in USD after the debit. Only present for session-paid requests.

Error responses

StatusError codeDescription
400unknown_pluginNo pricing configured for the requested plugin (session billing only)
401UnauthorizedAuthentication required for a protected plugin and no valid session, MPP credential, or payment session
402payment_requiredMPP payment required. Response includes challenge and pricing.
402session_requiredSession billing was requested but X-Session-Id or X-Wallet-Address header is missing
402session_invalidNo active session found for the provided session ID and wallet address
402insufficient_balanceSession balance is too low to cover the plugin price. Response includes session.remaining and session.cost.
402voucher_failedThe off-chain voucher could not be processed (e.g., concurrent debit race)
500internalInternal server error
502no_pluginNo plugin registered for the given ID

Gateway chat proxy

POST /api/gateway/chat
Sends a chat message to the caller’s deployed agent by enqueuing it as a job on the backend control plane. The server validates the user’s agent, applies rate limiting and workload gating, and returns a job ID that you poll for the result.
This endpoint no longer connects to the gateway via WebSocket. Chat messages are enqueued as asynchronous jobs on the backend. Use the returned jobId to poll for the result via GET /api/jobs/:jobId.
Requires session authentication. Subject to rate limiting (per-IP) and workload gating (per-user). Messages longer than 800 characters consume 2 workload slots; shorter messages consume 1.

Request body

FieldTypeRequiredDescription
messagestringYesMessage to send
{
  "message": "Summarize my tasks"
}
The sessionKey parameter has been removed. Chat sessions are now managed server-side by the backend job processor.

Response (202 Accepted)

{
  "success": true,
  "queued": true,
  "jobId": "job_abc123",
  "status": "queued",
  "agentId": "inst_a1b2c3d4e5",
  "agentName": "my-agent"
}
FieldTypeDescription
successbooleanAlways true on success
queuedbooleanAlways true — the message was enqueued
jobIdstringJob identifier. Poll GET /api/jobs/:jobId to retrieve the result.
statusstring"queued" — the job is waiting to be processed
agentIdstringThe user’s OpenClaw instance identifier
agentNamestringName of the agent

Errors

CodeDescription
400Message required — the message field is missing
401Unauthorized — no valid session
404User not found — authenticated user does not exist
404No OpenClaw instance found — the user has no provisioned OpenClaw instance
404No agent found — the user has no deployed agent
429Too many requests — rate limit or workload gate exceeded. Response may include retryAfterSeconds.
500Chat failed — error enqueuing the job
502Backend job queue returned an error or non-JSON response
503No gateway token available — no per-user gateway token was found in the database and no shared OPENCLAW_GATEWAY_TOKEN environment variable is configured

Example

curl -X POST https://agentbot.sh/api/gateway/chat \
  -H "Content-Type: application/json" \
  -H "Cookie: next-auth.session-token=YOUR_SESSION" \
  -d '{"message": "What is my agent status?"}'

Gateway status

GET /api/gateway/status
Requires session authentication. Returns a combined view of gateway health, active sessions, and cron jobs scoped to the authenticated user’s gateway. The server resolves the user’s per-user gateway URL and token from the database before invoking gateway tools. Use this endpoint to get a real-time snapshot of the gateway’s operational state.

Response

{
  "health": "healthy",
  "healthDetail": {
    "ok": true,
    "status": "healthy"
  },
  "sessions": {
    "total": 5,
    "active": 3,
    "list": [
      {
        "sessionKey": "main",
        "status": "active",
        "messageCount": 24,
        "lastActivity": "2026-03-30T01:15:00Z"
      }
    ]
  },
  "cron": {
    "total": 2,
    "enabled": 1,
    "jobs": [
      {
        "id": "heartbeat",
        "name": "Heartbeat",
        "enabled": true,
        "schedule": { "kind": "every", "everyMs": 1800000 },
        "lastRun": "2026-03-30T01:00:00Z",
        "nextRun": "2026-03-30T01:30:00Z"
      }
    ]
  }
}
FieldTypeDescription
healthstringOverall gateway health: healthy or unreachable
healthDetailobjectRaw health check result. Contains ok (boolean) and status or error fields.
sessions.totalnumberTotal number of sessions on the gateway
sessions.activenumberNumber of sessions with recent activity
sessions.listarrayUp to 10 recent sessions
cron.totalnumberTotal number of cron jobs
cron.enablednumberNumber of enabled cron jobs
cron.jobsarrayUp to 10 cron jobs

Errors

CodeDescription
401Unauthorized — no valid session

Example

curl -X GET https://agentbot.sh/api/gateway/status \
  -H "Cookie: next-auth.session-token=YOUR_SESSION"

Production gateway service

The production gateway is a modular Express application deployed on Railway that manages the OpenClaw gateway process. It provides a setup UI for initial configuration, an admin dashboard for monitoring, device pairing, and persistent storage on a Railway volume at /data. The wrapper proxies HTTP and WebSocket traffic to the internal OpenClaw gateway on 127.0.0.1:18789.

Wrapper authentication

Most wrapper management endpoints require admin authentication. When the WRAPPER_ADMIN_PASSWORD environment variable is set, requests must include one of:
  • Cookie: ocw_admin cookie set via the /login page (browser sessions)
  • Bearer token: Authorization: Bearer <password> header (API calls)
  • Legacy header: x-admin-token: <password> header
When WRAPPER_ADMIN_PASSWORD is not set, all management endpoints are accessible without authentication. Browser requests without valid credentials are redirected to /login. API requests receive a 401 JSON response.

Wrapper endpoints

The wrapper exposes the following management endpoints on its public port. All other requests are proxied to the internal OpenClaw gateway.

Gateway status

GET /api/status
No authentication required. Returns gateway state, uptime, and configuration status. Railway uses this endpoint as the container health check.
Response
{
  "state": "running",
  "running": true,
  "configured": true,
  "uptime": 3600.5,
  "terminalSessions": 2,
  "gatewayToken": "abc123...",
  "aiProvider": "google/gemini-2.5-flash",
  "runtime": {
    "ffmpeg": {
      "available": true,
      "version": "6.1.1"
    }
  },
  "ts": "2026-04-05T12:00:00.000Z"
}
FieldTypeDescription
statestringGateway process state: running, starting, stopped, or crashed
runningbooleantrue when the gateway process is running
configuredbooleanAlways true
uptimenumberWrapper process uptime in seconds
terminalSessionsnumberNumber of active WebSocket terminal sessions. Returns 0 when the terminal feature is unavailable. See WebSocket proxy.
gatewayTokenstring | nullThe configured gateway authentication token, or null if not set
aiProviderstring | nullThe primary model configured in the gateway, or null if not configured
runtimeobjectRuntime capabilities of the managed container
runtime.ffmpeg.availablebooleanWhether ffmpeg is installed and accessible in the container. Required for autonomous baseFM DJ broadcasting.
runtime.ffmpeg.versionstring | nullThe ffmpeg version string, or null when ffmpeg is not available
tsstringISO 8601 timestamp of the status check
The previous online and logsCount fields have been replaced. Use running instead of online and GET /api/logs to retrieve log data.

Gateway logs

GET /api/logs
Requires admin authentication. Returns the last N lines of gateway process output.
Query parameters
ParameterTypeDefaultDescription
linesnumber100Number of log lines to return. Maximum 500.
Response
{
  "logs": [
    {
      "ts": "2026-04-05T12:00:00.000Z",
      "stream": "stdout",
      "line": "Gateway ready on port 18789"
    }
  ]
}
FieldTypeDescription
logsarrayArray of log entry objects
logs[].tsstringISO 8601 timestamp of the log entry
logs[].streamstringOutput stream: stdout or stderr
logs[].linestringLog line content

Live log stream

GET /api/logs/stream
Requires admin authentication. Server-Sent Events (SSE) stream of gateway log output. On connection, the last 50 log entries are sent as history, followed by real-time log entries as they occur.
Event format
Each event is a JSON object with the same shape as entries in GET /api/logs:
{
  "ts": "2026-04-05T12:00:00.000Z",
  "stream": "stdout",
  "line": "Gateway ready on port 18789"
}

Gateway state events

GET /api/events
Requires admin authentication. Server-Sent Events (SSE) stream of gateway state changes. On connection, the current state is sent immediately, followed by real-time state change events.
Event format
{
  "state": "running"
}
FieldTypeDescription
statestringGateway process state: running, starting, stopped, or crashed

Restart gateway

POST /api/gateway/restart
Requires admin authentication. Stops the gateway process and restarts it.
The endpoint path has changed from POST /api/restart to POST /api/gateway/restart.
Response (200)
{
  "ok": true,
  "message": "Gateway restarting..."
}
Error response (500)
{
  "ok": false,
  "error": "Restart failed: gateway process not found"
}

Stop gateway

POST /api/gateway/stop
Requires admin authentication. Stops the gateway process without restarting it.
Response (200)
{
  "ok": true,
  "message": "Gateway stopped."
}
Error response (500)
{
  "ok": false,
  "error": "Stop failed: ..."
}

Read gateway configuration

GET /api/config
Requires admin authentication. Returns the current openclaw.json configuration with sensitive fields redacted.
Response (200)
{
  "ok": true,
  "config": {
    "agents": {
      "defaults": {
        "model": { "primary": "google/gemini-2.5-flash" },
        "workspace": "/data/.openclaw/workspace"
      }
    },
    "gateway": {
      "mode": "local",
      "bind": "loopback",
      "port": 18789
    }
  }
}
Sensitive fields (botToken, token, appToken, apiKey, password, serviceAccount, secret, key, auth) are replaced with [redacted] in the response.
Errors
CodeDescription
401Unauthorized
404No configuration file found

Update gateway configuration

POST /api/config
Requires admin authentication. Writes the provided JSON object as the new openclaw.json configuration. The gateway hot-reloads the configuration automatically.
Request body
The full configuration object to write. Must be a JSON object.
Response (200)
{
  "ok": true,
  "message": "Config written. Hot reload in progress..."
}
Errors
CodeDescription
400Invalid config body (not an object)
401Unauthorized
500Failed to write configuration

Device pairing

The wrapper provides endpoints for managing device pairing requests. All pairing endpoints require admin authentication.

List pending pairing requests

GET /api/pairing/pending
Response (200)
{
  "ok": true,
  "pending": [
    {
      "id": "req_abc123",
      "name": "Chrome on macOS",
      "ip": "192.168.1.42",
      "role": "viewer",
      "createdAt": "2026-04-05T12:00:00.000Z",
      "expiresAt": "2026-04-05T12:10:00.000Z"
    }
  ]
}
FieldTypeDescription
okbooleanAlways true on success
pendingarrayArray of pending pairing request objects
pending[].idstringUnique request identifier. Also accessible as requestId.
pending[].namestringDevice display name. Also accessible as deviceName.
pending[].ipstringRemote IP address of the requesting device. Also accessible as remoteIp.
pending[].rolestringRequested access role (for example viewer, admin)
pending[].createdAtstringISO 8601 timestamp of when the request was created
pending[].expiresAtstring | undefinedISO 8601 timestamp of when the request expires. When present, the admin dashboard displays a countdown timer.

Approve a pairing request

POST /api/pairing/approve
Request body
FieldTypeRequiredDescription
requestIdstringYesThe pairing request ID to approve
Response (200)
{
  "ok": true,
  "message": "Request abc123 approved"
}

Reject a pairing request

POST /api/pairing/reject
Request body
FieldTypeRequiredDescription
requestIdstringYesThe pairing request ID to reject
Response (200)
{
  "ok": true,
  "message": "Request abc123 rejected"
}

Revoke a paired device

POST /api/pairing/revoke
Request body
FieldTypeRequiredDescription
deviceIdstringYesThe device ID to revoke
rolestringYesThe device role to revoke
Response (200)
{
  "ok": true,
  "message": "Device abc123 revoked"
}

List paired devices

GET /api/pairing/paired
Response (200)
{
  "ok": true,
  "paired": [
    {
      "id": "dev_abc123",
      "name": "Chrome on macOS",
      "role": "viewer",
      "pairedAt": "2026-04-05T12:01:00.000Z"
    }
  ]
}
FieldTypeDescription
okbooleanAlways true on success
pairedarrayArray of paired device objects
paired[].idstringUnique device identifier. Also accessible as deviceId.
paired[].namestringDevice display name. Also accessible as deviceName.
paired[].rolestringAccess role assigned to the device
paired[].pairedAtstringISO 8601 timestamp of when the device was paired

Pairing event stream

GET /api/pairing/stream
Requires admin authentication. Server-Sent Events (SSE) stream of real-time pairing updates. On connection, the current list of pending requests is sent immediately, followed by change events as they occur.
Event format
Pending list update — sent on connection and whenever the pending list changes (for example when a new pairing request arrives):
{
  "type": "pending",
  "pending": [
    {
      "id": "req_abc123",
      "name": "Chrome on macOS",
      "ip": "192.168.1.42",
      "role": "viewer",
      "createdAt": "2026-04-05T12:00:00.000Z",
      "expiresAt": "2026-04-05T12:10:00.000Z"
    }
  ]
}
Pairing action update — sent when a pairing request is approved, rejected, or a paired device is revoked:
{
  "type": "update",
  "action": "approved",
  "requestId": "req_abc123"
}
FieldTypeDescription
typestringEvent type: pending or update
pendingarrayFull list of pending requests. Only present when type is pending. See list pending pairing requests for the object shape.
actionstringAction that occurred: approved, rejected, or revoked. Only present when type is update.
requestIdstringThe pairing request ID that was approved or rejected. Present when action is approved or rejected.
deviceIdstringThe device ID that was revoked. Present when action is revoked.

Setup flow

The wrapper provides a setup UI for initial gateway configuration. When the gateway is not yet configured, requests to / are redirected to /setup.

Setup page

GET /setup
No authentication required. Serves the setup UI HTML. Redirects to / if the gateway is already running.

Save setup configuration

POST /setup/save
No authentication required. Validates the setup form, writes the configuration and environment files, and launches the gateway.
Request body
FieldTypeRequiredDescription
providerstringYesModel provider: anthropic, openai, google, openrouter, groq, moonshot, zai, minimax, or ollama
apiKeystringConditionalAPI key for the selected provider. Required for all providers except ollama.
ollamaUrlstringConditionalOllama base URL (e.g., http://localhost:11434). Required when provider is ollama.
modelstringConditionalModel to use. Required for ollama. Optional for other providers (defaults to provider-specific model).
fallbackModelstringNoFallback model ID
telegramBotTokenstringNoTelegram bot token
telegramDmPolicystringNoTelegram DM policy: pairing, allowlist, open, or disabled. Defaults to pairing.
telegramAllowFromstringNoComma-separated list of allowed Telegram users
telegramWebhookUrlstringNoTelegram webhook URL
discordBotTokenstringNoDiscord bot token
discordDmPolicystringNoDiscord DM policy: pairing, allowlist, open, or disabled. Defaults to pairing.
discordAllowFromstringNoComma-separated list of allowed Discord users
slackBotTokenstringNoSlack bot token (requires slackAppToken)
slackAppTokenstringNoSlack app token (requires slackBotToken)
slackDmPolicystringNoSlack DM policy: pairing, allowlist, open, or disabled. Defaults to pairing.
mattermostUrlstringNoMattermost server URL (requires mattermostToken)
mattermostTokenstringNoMattermost token (requires mattermostUrl)
mattermostTeamstringNoMattermost team name
sessionScopestringNoSession scope: main, per-peer, per-channel-peer, or per-account-channel-peer. Defaults to per-channel-peer.
sessionResetModestringNoSession reset mode: off, daily, or idle
sessionResetHourstringNoHour (UTC) for daily session reset
Response (200)
{
  "ok": true,
  "message": "Config saved. Gateway launching..."
}
Errors
CodeDescription
400Validation errors. Response includes an errors array with descriptive messages.
409Gateway is already running or starting. Use POST /api/config to update configuration instead.
500Failed to write configuration or launch gateway

Get Ollama configuration

GET /setup/api/ollama-config
No authentication required. Returns the pre-configured Ollama base URL from environment variables.
Response
{
  "ollamaBaseUrl": "http://ollama.railway.internal:11434"
}

List Ollama models

GET /setup/api/ollama-models
No authentication required. Proxies to an Ollama instance to fetch available models.
Query parameters
ParameterTypeRequiredDescription
urlstringNoOllama base URL. Falls back to the OLLAMA_BASE_URL environment variable if not provided.
Response (200)
{
  "models": ["llama3.3", "deepseek-r1:1.5b"]
}
Errors
CodeDescription
400No Ollama URL provided or invalid URL format
502Could not reach Ollama instance or request timed out

Approve channel pairing via setup

POST /setup/pairing/approve
No authentication required. Approves a channel pairing code during initial setup.
Request body
FieldTypeRequiredDescription
channelstringYesChannel name
codestringYesPairing code
Response (200)
{
  "ok": true,
  "output": "Pairing approved"
}

Reset gateway

POST /setup/reset
No authentication required. Stops the gateway and resets configuration.
Request body
FieldTypeRequiredDescription
modestringNoReset mode: omit for config-only reset, or full for factory reset (wipes all data)
Response (200)
Config-only reset:
{
  "ok": true,
  "message": "Config reset complete. Redirecting to setup..."
}
Full factory reset:
{
  "ok": true,
  "message": "Full reset complete. All data wiped. Redirecting to setup..."
}

Export gateway data

GET /setup/export
No authentication required. Downloads a zip archive of all gateway data. When WRAPPER_ADMIN_PASSWORD is set, the zip is password-protected with the admin password.
Response
Returns a application/zip file as a download attachment. The Content-Disposition header includes a filename in the format openclaw-export-<timestamp>.zip.
Errors
CodeDescription
404No data directory found to export
500Failed to create export archive

Proxy error response (503)

When a request is proxied to the gateway but the gateway is not running, the wrapper returns a 502 error:
{
  "error": "Gateway not reachable",
  "detail": "connect ECONNREFUSED 127.0.0.1:18789"
}

WebSocket proxy

The wrapper handles WebSocket upgrade requests with path-based routing:
  • /ws/terminal — Routed to the built-in terminal WebSocket service, which provides an interactive terminal session to the container. This feature is optional — it requires node-pty to be installed in the container. When node-pty is not available, the terminal service is disabled and connections to /ws/terminal receive an error message indicating the feature is unavailable. The terminalSessions field in GET /api/status returns 0 when the terminal is disabled.
  • All other paths — Proxied to the internal OpenClaw gateway. The wrapper injects the Authorization: Bearer <token> header automatically.
The node-pty native module is dynamically loaded at startup. If it cannot be compiled or is not present in the container image, the gateway logs a warning (node-pty not available — terminal feature disabled) and continues operating normally. All other gateway features remain functional. To enable the terminal, ensure node-pty is installed and its native bindings can compile for the target platform.
When the gateway is not running, non-terminal WebSocket upgrade requests are proxied to the gateway address, which returns a connection error.

Terminal WebSocket messages

Messages on the /ws/terminal WebSocket are JSON objects with a type field.
Client-to-server messages
TypeFieldsDescription
inputdata (string)Send keystrokes or pasted text to the terminal
resizecols (number), rows (number)Notify the server that the terminal dimensions have changed
Server-to-client messages
TypeFieldsDescription
outputdata (string)Terminal output to render
exitcode (number)The terminal process exited with the given exit code

Environment variables

VariableDefaultDescription
OPENCLAW_GATEWAY_TOKEN(empty)Bearer token for authenticating proxied requests to the internal gateway. When not set, a random 64-character hex token is generated at startup.
PORT3000Port the wrapper listens on
OPENCLAW_DATA_DIR/dataRoot directory for persistent storage. The OpenClaw configuration and workspace are stored under {OPENCLAW_DATA_DIR}/.openclaw/. This should be a Railway volume mount.
WRAPPER_ADMIN_PASSWORD(empty)Password for accessing the admin dashboard and protected API endpoints. When not set, all management endpoints are accessible without authentication. See wrapper authentication.
OLLAMA_BASE_URL(empty)Ollama base URL (e.g., http://ollama.railway.internal:11434). Pre-fills the Ollama URL field in the setup UI and is used as the default for the Ollama models endpoint.
GEMINI_API_KEY(empty)Google Gemini API key. Written into the gateway .env file at startup for model authentication.
OPENROUTER_API_KEY(empty)OpenRouter API key for LLM provider authentication. Written into the gateway .env file at startup.

OpenClaw configuration and secrets

The wrapper writes an openclaw.json configuration file to {OPENCLAW_DATA_DIR}/.openclaw/openclaw.json at startup. API keys are stored separately in {OPENCLAW_DATA_DIR}/.openclaw/.env to keep secrets out of the JSON configuration file. The gateway reads both files at startup.
.env variableDescription
GEMINI_API_KEYGoogle Gemini API key for model authentication. Populated from the GEMINI_API_KEY container environment variable at startup.
OPENROUTER_API_KEYOpenRouter API key for LLM provider authentication. Populated from the OPENROUTER_API_KEY container environment variable at startup.

Default model configuration

The production gateway configures the following model default:
ParameterValueDescription
agents.defaults.model.primarygoogle/gemini-2.5-flashPrimary model for agent requests
When you use the setup UI to configure the gateway, the primary model is set based on your chosen provider. If you do not specify a model, the following defaults are used:
ProviderDefault model
anthropicanthropic/claude-opus-4-6
openaiopenai/gpt-5.4
googlegoogle/gemini-2.5-pro
openrouteropenrouter/auto
groqgroq/llama-3.3-70b-versatile
moonshotmoonshot/kimi-k2.5
zaizai/glm-4.5
minimaxminimax/MiniMax-M2.7
ollama(must be specified)

Agent defaults

ParameterValueDescription
agents.defaults.workspace{OPENCLAW_DATA_DIR}/.openclaw/workspaceDefault workspace directory inside the persistent volume
agents.defaults.userTimezoneEurope/LondonDefault timezone
agents.defaults.thinkingDefaultlowDefault thinking verbosity level
agents.defaults.verboseDefaultoffDefault verbose output mode
agents.defaults.timeoutSeconds600Maximum time in seconds for a single request
agents.defaults.maxConcurrent3Maximum concurrent agent tasks
agents.defaults.heartbeat.every30mSelf-monitoring heartbeat interval
agents.defaults.heartbeat.lightContexttrueUse minimal context for heartbeat checks
agents.defaults.heartbeat.isolatedSessiontrueRun heartbeat in an isolated session to avoid polluting active conversations

Tool configuration

ParameterValueDescription
tools.profilecodingTool profile loaded by default
tools.exec.backgroundMs10000Maximum time in milliseconds a background process can run
tools.exec.timeoutSec1800Maximum execution time in seconds for foreground commands (30 minutes)
tools.web.search.enabledtrueWeb search tool is available
tools.web.fetch.enabledtrueWeb fetch tool is available
tools.web.fetch.maxChars50000Maximum characters returned from web fetch requests

Session configuration

ParameterValueDescription
session.scopeper-senderEach sender gets an isolated conversation session
session.reset.modedailySessions reset on a daily schedule
session.reset.atHour4Hour (UTC) when daily session reset occurs
session.maintenance.modewarnLog warnings when sessions exceed size limits instead of force-pruning
session.maintenance.pruneAfter30dInactive sessions are pruned after 30 days
session.maintenance.maxEntries500Maximum entries per session before maintenance triggers

Cron configuration

ParameterValueDescription
cron.enabledtrueScheduled task execution is enabled
cron.maxConcurrentRuns2Maximum number of cron jobs that can run simultaneously
cron.sessionRetention24hHow long cron session data is retained after completion

Logging configuration

ParameterValueDescription
logging.levelinfoMinimum log level written to persistent storage
logging.consoleLevelinfoMinimum log level written to stdout
logging.consoleStylecompactLog output format (compact omits timestamps and metadata for cleaner output)

Gateway settings

ParameterValueDescription
gateway.modelocalGateway operating mode
gateway.bindloopbackBind address. The internal gateway binds to loopback only; the wrapper handles external traffic and proxies it to 127.0.0.1:18789.
gateway.port18789Internal gateway port
gateway.auth.tokenAuto-generated or OPENCLAW_GATEWAY_TOKENGateway authentication token. Written directly into the configuration when OPENCLAW_GATEWAY_TOKEN is set.
gateway.trustedProxies["127.0.0.1", "::1"]IP addresses trusted as reverse proxies. Includes IPv4 and IPv6 loopback only, since all external traffic passes through the local Express wrapper.
gateway.controlUi.allowedOrigins["*"]Permitted WebSocket origins. Set to ["*"] to allow connections from any origin.
gateway.controlUi.allowInsecureAuthtrueAllows the gateway to accept token-based auth from the wrapper proxy without requiring device pairing for browser sessions.
gateway.reload.modehybridConfiguration reload strategy

Health check

The container image is configured with a Docker HEALTHCHECK that probes GET /api/status every 15 seconds (5-second timeout, 60-second start period, 5 retries). Railway uses the same path (/api/status) for health monitoring and will restart the container on failure.

Persistent storage

The wrapper stores all OpenClaw state under {OPENCLAW_DATA_DIR}/.openclaw/ (default: /data/.openclaw/). This directory should be backed by a Railway volume mount so that configuration, conversations, and workspace files survive container restarts.

Process management

The wrapper manages the OpenClaw gateway process with automatic restart on crash. When the gateway exits unexpectedly, the wrapper schedules a restart with exponential backoff starting at 2 seconds, doubling each attempt, up to a maximum of 30 seconds. The gateway is considered ready when it accepts TCP connections on port 18789. If the gateway does not become ready within 60 seconds, the wrapper marks it as crashed and schedules another restart attempt.

Control UI URL resolution

The dashboard constructs control UI links (for the chat, skills, and config views) using the user’s own gateway URL as the base origin. When a user has a deployed gateway instance, the openclawUrl stored in their account is used to derive the control UI base URL. The platform default gateway URL is only used as a fallback when no user-specific URL is available.

URL construction

The control UI URL is built from the following components:
ComponentSourceDescription
Base originUser’s openclawUrlThe origin (scheme + host) of the user’s deployed gateway. Falls back to the platform default OPENCLAW_GATEWAY_URL when not set.
View path/chat, /skills, or /configThe control UI view to open
Query parametersView-specificFor the chat view, includes session (defaults to main)
Hash fragmentGateway credentialsContains token (gateway auth token) and gatewayUrl (WebSocket URL). Passed in the URL fragment so they are never sent to the server.

Example

For a user with openclawUrl set to https://my-agent.up.railway.app:
https://my-agent.up.railway.app/chat?session=main#token=abc123&gatewayUrl=wss%3A%2F%2Fmy-agent.up.railway.app
When openclawUrl is not set, the platform default gateway URL is used instead:
https://gateway.agentbot.sh/chat?session=main#token=abc123&gatewayUrl=wss%3A%2F%2Fgateway.agentbot.sh
The gateway token and WebSocket URL are passed in the URL hash fragment, which is never sent to the server in HTTP requests. This ensures credentials remain client-side only.

WebSocket URL derivation

The WebSocket gateway URL is derived from the user’s gateway URL by replacing the scheme with wss:// and using the same host. For example, https://my-agent.up.railway.app becomes wss://my-agent.up.railway.app.

Per-agent gateway authentication

Each agent container receives a unique gateway auth token at provisioning time. The internal gateway authenticates requests using token-based auth on port 18789.
FieldDescription
gateway.auth.modetoken
gateway.auth.tokenUnique hex token auto-generated per container. The container manager and Railway provisioning paths generate a 64-character token (32 bytes of entropy). The backend provisioning path generates a 48-character token (24 bytes of entropy). A 64-character token (32 bytes) is generated at startup if no token is passed via the OPENCLAW_GATEWAY_TOKEN environment variable.
gateway.port18789

Token resolution order

When the platform sends requests to a user’s gateway (for example, the gateway chat proxy or gateway status endpoints), the server resolves the authentication token in the following order:
  1. Per-user gateway token — the server looks up the authenticated user’s gateway URL from the database. If a per-user URL is found, the token associated with that user’s gateway is used.
  2. Shared gateway token — if no per-user gateway is found, the server falls back to the OPENCLAW_GATEWAY_TOKEN environment variable.
If neither source provides a token, the request fails with a 503 error. This resolution order ensures that each user’s gateway traffic is authenticated with their own token rather than a single shared credential.
The container startup process writes its own minimal configuration to $HOME/.openclaw/openclaw.json using a slightly different schema (auth.method at the top level instead of gateway.auth.mode). The provisioning config written by the backend uses the gateway.auth.mode path. When the container starts, it overwrites the provisioning config with its own minimal skeleton. All provisioning paths include a top-level env section containing OPENROUTER_API_KEY so the OpenClaw runtime can authenticate with the LLM provider. To preserve the full provisioning config, pass the gateway token via the OPENCLAW_GATEWAY_TOKEN environment variable so the startup process uses the same token.

Agent container configuration

When an agent is provisioned, the backend generates an OpenClaw configuration with the following parameters. These values are set automatically and cannot be overridden by the caller.

OpenClaw configuration env section

Each agent container’s openclaw.json includes a top-level env section that passes secrets to the OpenClaw runtime. All three provisioning paths (production gateway startup, Railway direct provisioning, and backend container manager) write this section into the configuration file at launch.
ParameterDescription
env.OPENROUTER_API_KEYOpenRouter API key for LLM provider authentication. Populated from the OPENROUTER_API_KEY container environment variable. Required for the agent to make model requests through OpenRouter.
The env section in openclaw.json is distinct from the container-level environment variables listed below. Container environment variables are set on the container process by the orchestrator (Railway or Docker). The env section is read by the OpenClaw runtime from its configuration file and used internally for service authentication. Both mechanisms deliver the same OPENROUTER_API_KEY value, but the config-file path ensures OpenClaw can access the key even when the runtime does not inherit the container’s full environment.

Container environment variables

The following environment variables are set on every agent container at launch. Variables are grouped by source — some are set by the container startup process (local Docker path) and others are injected by the provisioning service (Railway path). When both paths set the same variable, the provisioning service value takes precedence.
VariableDefaultDescription
NODE_ENVproductionNode.js environment. Set by the provisioning service.
PORTRailway-assignedPort the agent process listens on inside the container. This value is injected by Railway automatically and is no longer set by the provisioning service. A TCP proxy inside the container forwards traffic from the Railway-assigned port to the OpenClaw gateway on 127.0.0.1:18789.
HOME/rootHome directory for the container user. Managed runtime containers run as root with the OpenClaw data directory at /root/.openclaw.
TERMxterm-256colorTerminal type
NODE_COMPILE_CACHE/var/tmp/openclaw-compile-cacheDirectory for the Node.js compile cache. Speeds up cold starts by caching compiled bytecode across process restarts.
OPENCLAW_NO_RESPAWN1When set to 1, prevents the OpenClaw process from automatically respawning after exit. Container-level restart policies (Docker --restart or orchestrator health checks) handle process recovery instead.
OPENCLAW_GATEWAY_TOKENAuto-generatedGateway authentication token. When not set, a 64-character hex token (32 bytes of entropy) is generated at startup. See per-agent gateway authentication.
OPENCLAW_GATEWAY_URLhttp://openclaw-gateway-lqma:10000Gateway URL for the agent to communicate with the platform gateway. Set by the provisioning service. When this variable is not configured, the provisioning endpoint falls back to the default internal Railway DNS address shown here. You can override this value to point to a custom gateway deployment.
OPENCLAW_GATEWAY_PORT18789Port the gateway listens on inside the container
OPENCLAW_GATEWAY_BINDDeprecated. Previously set to 0.0.0.0 to allow Railway’s reverse proxy to route traffic into the container. This variable is no longer injected by the provisioning service because it has no effect on OpenClaw. Traffic now reaches the gateway through a TCP proxy that forwards the Railway-assigned PORT to 127.0.0.1:18789.
OPENCLAW_BINDDeprecated. Previously used as a fallback bind address when OPENCLAW_GATEWAY_BIND was not set. This variable is no longer injected by the provisioning service.
AGENTBOT_USER_IDPer-userOwner user ID passed at provisioning time
AGENTBOT_PLANsoloSubscription plan tier (solo, collective, label, or network)
AGENTBOT_API_URLhttps://agentbot-backend-production.up.railway.appBackend API URL for the agent to call platform services. Set by the provisioning service.
AGENTBOT_MODEhomeInstallation mode (home for self-hosted, link for existing OpenClaw)
AGENTBOT_API_KEYPer-userAPI key for authenticating with the Agentbot platform
DATABASE_URLPlatform-providedPostgreSQL connection string for agent data persistence. Set by the provisioning service.
OPENROUTER_API_KEYPlatform-providedOpenRouter API key for AI model access. Set by the provisioning service.
INTERNAL_API_KEYPlatform-providedInternal API key for authenticating agent-to-platform requests. Set by the provisioning service.
WALLET_ENCRYPTION_KEYPlatform-providedEncryption key for securing agent wallet data at rest. Set by the provisioning service.
CONTROL_UI_ORIGIN(empty)Primary origin allowed to connect to the Control UI via WebSocket. When not set, falls back to NEXT_PUBLIC_APP_URL, then https://agentbot.sh.
CONTROL_UI_COMPAT_ORIGIN(empty)Optional secondary origin for Control UI WebSocket connections. When set, this origin is added alongside the primary origin in the controlUi.allowedOrigins list.

Gateway settings

ParameterValueDescription
gateway.modelocalGateway operating mode
gateway.bindlanBind address for the gateway. Set to lan so the gateway listens on all interfaces inside the Docker container, which is required for port-mapped containers where the host forwards traffic to the container’s published port. On Railway-provisioned containers, a TCP proxy may still forward traffic from the Railway-assigned PORT to 127.0.0.1:18789.
gateway.port18789Internal gateway port
gateway.auth.modetokenAuthentication mode
gateway.auth.rateLimit.maxAttempts10Maximum authentication attempts before lockout
gateway.auth.rateLimit.windowMs60000Rate limit window in milliseconds (1 minute)
gateway.auth.rateLimit.lockoutMs300000Lockout duration in milliseconds (5 minutes)
gateway.auth.rateLimit.exemptLoopbacktrueExempt loopback addresses from rate limiting
gateway.auth.allowTailscaletrueAllow Tailscale network connections
gateway.trustedProxies["127.0.0.1", "10.0.0.0/8", "100.64.0.0/10", "172.16.0.0/12", "192.168.0.0/16"]IP addresses trusted as reverse proxies. Requests from these addresses have their X-Forwarded-For headers honored for origin detection. Includes loopback, RFC 1918 private ranges, and the 100.64.0.0/10 CGNAT range used by Railway’s internal network.
gateway.http.endpoints.chatCompletions.enabledtrueEnables the OpenAI-compatible POST /v1/chat/completions endpoint on the gateway. Required for the REST-based POST /api/chat endpoint. Set during provisioning.
gateway.controlUi.enabledtrueGateway control UI is enabled in containers.
gateway.controlUi.allowedOriginsDerived from environmentOrigins permitted to connect to the Control UI via WebSocket. Defaults to the value of CONTROL_UI_ORIGIN (or NEXT_PUBLIC_APP_URL, falling back to https://agentbot.sh). An optional second origin can be added via CONTROL_UI_COMPAT_ORIGIN. When not configured, the gateway may reject WebSocket connections with an “origin not allowed” error if the request origin does not match.
gateway.controlUi.dangerouslyDisableDeviceAuthfalseWhen true, disables the interactive device authentication flow for the Control UI. Defaults to false — device auth is now required. For headless deployments where no browser is available, you may need to use token-based authentication instead of the device auth handshake.
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallbackfalseWhen true, allows the gateway to fall back to the Host header when the Origin header is missing from a WebSocket upgrade request. Defaults to false — the Origin header is now required.
The controlUi.allowedOrigins, controlUi.dangerouslyDisableDeviceAuth, and controlUi.dangerouslyAllowHostHeaderOriginFallback defaults have changed. Previously, allowedOrigins was set to ["*"], and both dangerouslyDisableDeviceAuth and dangerouslyAllowHostHeaderOriginFallback were true. The new defaults restrict origins to the platform URL and require device authentication and the Origin header for WebSocket connections.

Tool settings

ParameterValueDescription
tools.profilemessaging or codingmessaging for solo plan, coding for all other plans
tools.deny["browser", "canvas"]Tools disabled in container environments
tools.exec.allowedCommandsArray of whitelisted commandsCommands the agent is permitted to execute (includes git, node, npm, python3, curl, ls, cat, grep, find, wget, mkdir, cp, mv, rm, echo, date, whoami, chmod, chown, touch, head, tail, wc, sort, uniq, awk, sed, tar, zip, unzip, docker, ps, df, du)
tools.exec.allowedPaths["/root/.openclaw/workspace", "/tmp", "/root"]Filesystem paths the agent can access. Managed runtime containers run as root with configuration stored at /root/.openclaw/openclaw.json.
tools.exec.denyPaths["/etc/shadow", "/etc/passwd", "/proc", "/sys"]Filesystem paths the agent is blocked from accessing
tools.web.maxChars50000Maximum characters returned from web tool requests
tools.loopDetection.maxIterations20Maximum loop iterations before the agent is interrupted
tools.loopDetection.windowMinutes5Time window for loop detection

Session settings

ParameterValueDescription
session.maxTokens100000Maximum tokens per session
session.compaction.strategyautoAutomatic context compaction strategy
session.compaction.triggerAtPercent80Compaction triggers when token usage reaches this percentage

Agent defaults

ParameterValueDescription
agents.defaults.workspace/root/.openclaw/workspaceDefault workspace directory. Managed runtime containers mount a persistent volume at /root/.openclaw.
agents.defaults.imageMaxDimensionPx1200Maximum image dimension in pixels (optimizes vision token usage)
agents.defaults.userTimezoneEurope/LondonDefault timezone (overridden by signup timezone when available)
agents.defaults.timeFormat24hTime format
agents.defaults.compaction.maxMessages200Maximum messages before compaction
agents.defaults.compaction.keepLastN20Number of recent messages preserved after compaction
agents.defaults.heartbeat.every30mSelf-monitoring heartbeat interval
agents.defaults.skipBootstrapfalseWhether to skip the bootstrap phase
agents.defaults.bootstrapMaxChars4000Maximum characters for bootstrap content

Health monitoring

The gateway monitors channel health for each agent container. When a channel becomes unresponsive, the gateway can automatically restart it.
ParameterValueDescription
channelHealthCheckMinutes5Interval between health checks for each channel
channelStaleEventThresholdMinutes30Channel is considered stale if no events are received within this window
channelMaxRestartsPerHour10Maximum number of automatic channel restarts per hour

CORS

The gateway supports CORS preflight via OPTIONS /api/v1/gateway. Allowed methods are GET, POST, and OPTIONS. The Content-Type, Authorization, X-Plugin-Id, and Payment headers are permitted in the CORS configuration.
The X-Payment-Method, X-Session-Id, and X-Wallet-Address headers are read server-side but are not included in the CORS Access-Control-Allow-Headers response. Cross-origin requests that include these headers may be rejected by the browser preflight check. Same-origin requests are unaffected. If you need to send these headers from a different origin, configure the GATEWAY_CORS_ORIGIN environment variable or proxy the request through a same-origin endpoint.

OpenAI-compatible endpoints

The gateway exposes a set of endpoints that follow the OpenAI API format. These allow you to use Agentbot as a drop-in replacement for the OpenAI SDK or any tool that supports the OpenAI API shape.

List models

GET /v1/models
Returns all available models in OpenAI-compatible format. This endpoint is public and does not require authentication.

Response (200)

{
  "object": "list",
  "data": [
    {
      "id": "openrouter/openai/gpt-4o-mini",
      "object": "model",
      "created": 1742472000,
      "owned_by": "openrouter"
    }
  ]
}

Model object

FieldTypeDescription
idstringModel identifier (provider-prefixed)
objectstringAlways model
creatednumberUnix timestamp of when the response was generated
owned_bystringProvider that serves the model (e.g., openrouter, agentbot)

Errors

StatusDescription
500Failed to fetch models — an internal error occurred while retrieving the model list

Retrieve a model

GET /v1/models/:model
Returns details for a single model by its ID. This endpoint is public and does not require authentication.

Path parameters

ParameterTypeRequiredDescription
modelstringYesThe model ID to look up (e.g., openrouter/openai/gpt-4o-mini)

Response (200)

{
  "id": "openrouter/openai/gpt-4o-mini",
  "object": "model",
  "created": 1742472000,
  "owned_by": "openrouter"
}

Errors

StatusDescription
404Model {model} not found — no model matches the provided ID
500Failed to fetch model — an internal error occurred

Create embeddings

POST /v1/embeddings
Generates embeddings for the given input. Proxies the request to OpenRouter. Requires authentication.

Headers

HeaderTypeRequiredDescription
AuthorizationstringYesBearer token or session cookie
Content-TypestringYesMust be application/json

Request body

{
  "input": "The quick brown fox jumps over the lazy dog",
  "model": "openai/text-embedding-3-small"
}
FieldTypeRequiredDescription
inputstring or string[]YesText to generate embeddings for. Can be a single string or an array of strings.
modelstringNoEmbedding model to use. Defaults to openai/text-embedding-3-small.

Response (200)

The response follows the OpenAI embeddings format. The exact shape depends on the upstream provider.
{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [0.0023064255, -0.009327292, ...]
    }
  ],
  "model": "openai/text-embedding-3-small",
  "usage": {
    "prompt_tokens": 9,
    "total_tokens": 9
  }
}

Errors

StatusDescription
400input is required — the input field is missing from the request body
401Unauthorized — valid authentication is required
503Embeddings not configured — the server does not have an OpenRouter API key configured
500Embeddings request failed — the upstream provider returned an error

Rate limits

EndpointLimit
/api/v1/gateway100/min
/v1/models120/min (general)
/v1/models/:model120/min (general)
/v1/embeddings120/min (general)

Examples

Route a request to the agent plugin (Stripe)

curl -X POST https://agentbot.sh/api/v1/gateway \
  -H "Content-Type: application/json" \
  -H "X-Plugin-Id: agent" \
  -H "Cookie: next-auth.session-token=YOUR_SESSION" \
  -d '{"messages": [{"role": "user", "content": "Summarize my tasks"}]}'

Route a request with MPP payment

curl -X POST https://agentbot.sh/api/v1/gateway \
  -H "Content-Type: application/json" \
  -H "X-Plugin-Id: generate-text" \
  -H "Authorization: Payment {\"scheme\":\"Payment\",\"transaction\":\"0x76...\",\"challengeNonce\":\"abc123\"}" \
  -d '{"messages": [{"role": "user", "content": "Hello"}]}'

Route a request with session-based billing

curl -X POST https://agentbot.sh/api/v1/gateway \
  -H "Content-Type: application/json" \
  -H "X-Plugin-Id: agent" \
  -H "X-Payment-Method: session" \
  -H "X-Session-Id: ses_a1b2c3d4e5f6..." \
  -H "X-Wallet-Address: 0xd8fd0e1dce89beaab924ac68098ddb17613db56f" \
  -d '{"messages": [{"role": "user", "content": "Summarize my tasks"}]}'
The response includes the remaining session balance:
Payment-Receipt: session:ses_a1b2c3d4e5f6...:v_abc123def456
X-Session-Remaining: 9.95

List available models (OpenAI-compatible)

curl https://agentbot.sh/v1/models

Retrieve a specific model

curl https://agentbot.sh/v1/models/openrouter/openai/gpt-4o-mini

Generate embeddings

curl -X POST https://agentbot.sh/v1/embeddings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"input": "Hello world", "model": "openai/text-embedding-3-small"}'