Developer API

Programmatic API for managing your OpenClaw instance. Create API keys, start and stop instances, and poll async operations. Available on Pro and Business plans.

Base URL: https://www.myopenclaw.cloud/api/v1llms.txt →

Overview

The MyOpenClaw Developer API lets you manage your instance programmatically. All endpoints are under /api/v1 and require Bearer token authentication with an API key.

API access is available to Pro ($49/mo) and Business ($99/mo) subscribers. Keys are created from the Dashboard or via the API itself.

Quick Start

Get up and running in under a minute. You need a Pro or Business plan and an API key from the Dashboard.

1Set your API key

Store your key as an environment variable so it stays out of your code:

bash
export MOC_API_KEY="moc_abc123_yourSecretKeyHere"

2Check your instance status

Make your first API call to verify everything works. Replace alice with your username:

bash
curl -s -H "Authorization: Bearer $MOC_API_KEY" \
  https://www.myopenclaw.cloud/api/v1/instances/alice | jq
json
{
  "id": "uuid",
  "username": "alice",
  "status": "running",
  "domain": "alice.myopenclaw.cloud",
  "plan": "pro"
}

3Start or stop your instance

Control your instance with a single command:

bash
# Stop your instance
curl -X POST -H "Authorization: Bearer $MOC_API_KEY" \
  https://www.myopenclaw.cloud/api/v1/instances/alice/stop

# Start it back up (async — returns an operation ID)
curl -X POST -H "Authorization: Bearer $MOC_API_KEY" \
  https://www.myopenclaw.cloud/api/v1/instances/alice/start
Next steps: See full code examples for Python and JavaScript, or read about authentication and scopes for fine-grained key permissions.

Authentication

Include your API key as a Bearer token in the Authorization header:

http
Authorization: Bearer moc_<shortToken>_<longToken>

Key format

Keys use a three-part format: moc_<shortToken>_<longToken>

  • moc_ — fixed prefix for identification
  • shortToken — used for fast DB lookup (not secret)
  • longToken — HMAC-SHA256 hashed server-side; never stored in plaintext
Important: The full key is shown only once at creation time. Store it securely. Cookie-bearing requests are rejected to prevent confused-deputy attacks.

Scopes

Each API key has a set of scopes controlling what it can access:

ScopeDescription
instance:readRead instance status
instance:writeStart, stop, restart instances
provider:readRead provider/model configuration
provider:writeUpdate provider/model configuration
integrations:readRead integration settings
integrations:writeUpdate integration settings
agents:readRead agent configurations
agents:writeUpdate agent configurations
operations:readPoll async operation status
keys:readList and view API keys
keys:writeCreate and revoke API keys

Shortcuts

ShortcutExpands to
readAll :read scopes
writeAll scopes
allAll scopes

Rate Limits

Rate limits are enforced per API key and per user (global ceiling across all keys).

Per-key limits (requests per minute)

OperationProBusiness
Read (GET)120/min240/min
Write (POST, DELETE)30/min60/min
Heavy (start, restart)5/min10/min

Global ceiling (per user, all keys)

PlanLimit
Pro1,000/min
Business2,000/min

Response headers

  • X-RateLimit-Limit — Maximum requests allowed
  • X-RateLimit-Remaining — Requests remaining
  • X-RateLimit-Reset — Unix timestamp when window resets
  • Retry-After — Seconds to wait (on 429 responses)
Fail-closed: If the rate limiting service is unavailable, the API returns 503 rather than allowing unlimited requests.

Errors

All errors return a consistent JSON format:

json
{
  "error": "Human-readable message",
  "code": "ERROR_CODE"
}
HTTPCodeDescription
400VALIDATION_ERRORInvalid input
400NOT_PROVISIONEDInstance not fully provisioned
400CANNOT_REVOKE_SELFA key cannot revoke itself
401INVALID_API_KEYMissing, invalid, revoked, or expired key
402PAYMENT_REQUIREDSubscription needed
403PLAN_REQUIREDRequires Pro or Business plan
403INSUFFICIENT_SCOPEKey lacks required scope
403SCOPE_ESCALATIONCannot create key with broader scopes
404NOT_FOUNDResource not found
409ALREADY_RUNNINGInstance already running
409ALREADY_STOPPEDInstance already stopped
409NOT_RUNNINGInstance must be running
422KEY_LIMIT_REACHEDMax API keys reached
429RATE_LIMITEDToo many requests
500INTERNAL_ERRORServer error
503SERVICE_UNAVAILABLETemporary outage

Instances

GET/api/v1/instances/:instanceId

Get the current status of an instance. The :instanceId accepts a UUID or username.

Scope: instance:read

json
// Response 200
{
  "id": "uuid",
  "username": "alice",
  "subdomain": "alice.myopenclaw.cloud",
  "domain": "alice.myopenclaw.cloud",
  "status": "running",
  "plan": "pro",
  "fly_region": "dfw",
  "openclaw_version": "2026.2.26",
  "created_at": "2026-02-01T00:00:00.000Z",
  "updated_at": "2026-02-28T12:00:00.000Z"
}

Statuses: provisioning, pending_payment, running, stopped, failed

POST/api/v1/instances/:instanceId/start

Asynchronously starts a stopped instance. Returns 202 Accepted with an operation ID for polling.

Scope: instance:write · Optional: Idempotency-Key header

json
// Response 202
{
  "operation": {
    "id": "op_abc123def456",
    "type": "instance.start",
    "status": "pending",
    "created_at": "2026-03-01T00:00:00.000Z"
  },
  "links": {
    "poll": "/api/v1/operations/op_abc123def456"
  }
}

Errors: 409 ALREADY_RUNNING, 402 PAYMENT_REQUIRED, 400 NOT_PROVISIONED

POST/api/v1/instances/:instanceId/stop

Synchronously stops a running instance. Returns immediately.

Scope: instance:write

json
// Response 200
{
  "id": "uuid",
  "status": "stopped",
  "domain": "alice.myopenclaw.cloud"
}
POST/api/v1/instances/:instanceId/restart

Asynchronously restarts a running instance. Returns 202 Accepted.

Scope: instance:write · Optional: Idempotency-Key header

Error: 409 NOT_RUNNING

Operations

Async operations (start, restart) return a 202 with an operation ID. Poll this endpoint to check progress.

GET/api/v1/operations/:operationId

Poll the status of a single async operation. Pending/running operations include a Retry-After: 5 header. Completed operations include Cache-Control: public, max-age=3600.

Scope: operations:read

json
// Response 200 — succeeded
{
  "id": "op_abc123def456",
  "type": "instance.start",
  "status": "succeeded",
  "result": {
    "success": true,
    "domain": "alice.myopenclaw.cloud",
    "version": "2026.2.26"
  },
  "created_at": "2026-03-01T00:00:00.000Z",
  "completed_at": "2026-03-01T00:01:30.000Z"
}

// Response 200 — failed
{
  "id": "op_abc123def456",
  "type": "instance.start",
  "status": "failed",
  "error": {
    "code": "FLY_API_ERROR",
    "message": "Failed to start machine"
  },
  "created_at": "2026-03-01T00:00:00.000Z",
  "completed_at": "2026-03-01T00:00:45.000Z"
}
GET/api/v1/operations

List async operations for the authenticated user.

Query params: status (pending, running, succeeded, failed), limit (1-100, default 20)

json
// Response 200
{
  "operations": [ ... ],
  "has_more": false
}

API Keys

POST/api/v1/keys

Create a new API key. The full key is returned only once.

Scope: keys:write

json
// Request body
{
  "name": "CI/CD Pipeline",       // 1-64 characters, required
  "scopes": ["instance:read", "instance:write"],  // required
  "expires_in_days": 90            // 1-365, optional
}
json
// Response 201
{
  "id": "key_abc123",
  "name": "CI/CD Pipeline",
  "key": "moc_abc123_longSecretToken",
  "short_token": "abc123",
  "scopes": ["instance:read", "instance:write"],
  "last_used_at": null,
  "created_at": "2026-03-01T00:00:00.000Z",
  "expires_at": "2026-05-30T00:00:00.000Z",
  "revoked_at": null
}
Scope escalation prevention: A key cannot create a new key with broader scopes than it has itself.
GET/api/v1/keys

List all API keys for the authenticated user. Does not include secret material.

Scope: keys:read

GET/api/v1/keys/:keyId

Get a single API key by ID.

Scope: keys:read

DELETE/api/v1/keys/:keyId

Revoke an API key. Revocation is immediate and permanent. A key cannot revoke itself.

Scope: keys:write

json
// Response 200
{
  "id": "key_abc123",
  "revoked_at": "2026-03-01T12:00:00.000Z"
}

Idempotency

For async operations (start, restart), include an Idempotency-Key header to prevent duplicate operations:

http
Idempotency-Key: my-unique-key-123

If an operation already exists with the same idempotency key for your user, the existing operation is returned instead of creating a new one — regardless of the existing operation's current status.

Examples

Quick start (curl)

bash
# Get instance status
curl -H "Authorization: Bearer $MOC_KEY" \
  https://www.myopenclaw.cloud/api/v1/instances/alice

# Stop instance
curl -X POST -H "Authorization: Bearer $MOC_KEY" \
  https://www.myopenclaw.cloud/api/v1/instances/alice/stop

# Start instance (async — returns operation ID)
curl -X POST -H "Authorization: Bearer $MOC_KEY" \
  https://www.myopenclaw.cloud/api/v1/instances/alice/start

# Poll operation
curl -H "Authorization: Bearer $MOC_KEY" \
  https://www.myopenclaw.cloud/api/v1/operations/op_abc123

# Create a new API key
curl -X POST -H "Authorization: Bearer $MOC_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"My Key","scopes":["read"]}' \
  https://www.myopenclaw.cloud/api/v1/keys

# Revoke a key
curl -X DELETE -H "Authorization: Bearer $MOC_KEY" \
  https://www.myopenclaw.cloud/api/v1/keys/key_abc123

Polling pattern (Python)

python
import time
import requests

BASE = "https://www.myopenclaw.cloud/api/v1"
HEADERS = {"Authorization": "Bearer moc_xxx_yyy"}

# 1. Start the instance
resp = requests.post(f"{BASE}/instances/alice/start", headers=HEADERS)
operation = resp.json()["operation"]

# 2. Poll until complete
while operation["status"] in ("pending", "running"):
    time.sleep(5)  # Respect Retry-After header
    resp = requests.get(
        f"{BASE}/operations/{operation['id']}",
        headers=HEADERS
    )
    operation = resp.json()

# 3. Check result
if operation["status"] == "succeeded":
    print("Started:", operation["result"]["domain"])
else:
    print("Failed:", operation["error"]["message"])

Polling pattern (JavaScript)

javascript
const BASE = "https://www.myopenclaw.cloud/api/v1";
const headers = { Authorization: "Bearer moc_xxx_yyy" };

// 1. Start the instance
const startRes = await fetch(`${BASE}/instances/alice/start`, {
  method: "POST",
  headers,
});
let operation = (await startRes.json()).operation;

// 2. Poll until complete
while (["pending", "running"].includes(operation.status)) {
  await new Promise((r) => setTimeout(r, 5000));
  const pollRes = await fetch(
    `${BASE}/operations/${operation.id}`,
    { headers }
  );
  operation = await pollRes.json();
}

// 3. Check result
if (operation.status === "succeeded") {
  console.log("Started:", operation.result.domain);
} else {
  console.error("Failed:", operation.error.message);
}

Ready to get started?

Create your first API key from the Dashboard.