← API reference

Happy-path cookbook

Create (or ensure) a Medium VM, wait until it is usable, then SSH. Pin the OpenAPI spec in CI — field names below are stable on /v1.

Stable fields

Use id, name, plan, status (pending | running | stopped | error), ipAddress, and region. vmId is a deprecated alias of id.

Ready without polling

Subscribe to vm.ready on POST /webhooks (scope webhooks:manage). Verify X-SkyVM-Signature and X-SkyVM-Timestamp. Poll GET /vms/{id} only as a fallback.

Curl

export SKYVM_KEY=sk_live_...
export BASE=https://www.skyvm.cloud/api/v1

# Create a Medium named worker-1 (409 if the name exists)
curl -sS -X POST "$BASE/vms" \
  -H "Authorization: Bearer $SKYVM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan":"medium","name":"worker-1","password":"change-me-now"}'

# Prefer ensure for pooled workers — returns the existing box
curl -sS -X PUT "$BASE/vms/worker-1" \
  -H "Authorization: Bearer $SKYVM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plan":"medium","password":"change-me-now","healthCheck":{"port":8090,"path":"/health"}}'

# Poll until running + public IP (fallback if you skip webhooks)
# Host clone usually finishes within 3 minutes (API timeout 180s).
# Without healthCheck, running means the hypervisor is up.
# With healthCheck, running means GET :8090/health succeeded inside the guest.
ID=42
while true; do
  curl -sS "$BASE/vms/$ID" -H "Authorization: Bearer $SKYVM_KEY"
  sleep 15
done

ssh root@YOUR_PUBLIC_IP

Python

import os, time, requests

BASE = os.environ.get("SKYVM_API_BASE", "https://www.skyvm.cloud/api/v1")
KEY = os.environ["SKYVM_KEY"]
H = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}

r = requests.put(
    f"{BASE}/vms/worker-1",
    headers=H,
    json={
        "plan": "medium",
        "password": os.environ["SKYVM_VM_PASSWORD"],
        "healthCheck": {"port": 8090, "path": "/health"},
    },
)
r.raise_for_status()
vm = r.json()
vm_id = vm["id"]

for _ in range(40):
    vm = requests.get(f"{BASE}/vms/{vm_id}", headers=H).json()
    if vm.get("status") == "running" and vm.get("ipAddress"):
        print(vm["id"], vm["name"], vm["ipAddress"])
        break
    if vm.get("status") == "error":
        raise SystemExit(f"VM failed: {vm}")
    time.sleep(15)
else:
    raise SystemExit("timed out waiting for running + ipAddress")

print(f"ssh root@{vm['ipAddress']}")

Auth header is Authorization: Bearer sk_live_.... Missing or invalid keys return 401 unauthorized. A key without vms:write returns 403 forbidden. Duplicate POST /vms names return 409 name_taken. Rotate keys by revoking and creating a new one.

Trading notes · Changelog