Expanse API
Sign up
Reseller API

Endpoints

Every v1 operation with scope, request and response examples.

Before calling

Set BASE=https://panel.expanse.host/api/reseller/v1 and RESELLER_KEY to your secret rk_ key. Replace IDs and catalog values. Full bounds and schemas.

Send Authorization: Bearer rk_... on all operations except openapi.json. Write does not imply read. Foreign resources return not_found.

ScopeOperations
reseller.vms.readAccount, limits, catalog, locations, VM reads, stats, rDNS/rescue/backups GET, webhooks GET
reseller.vms.writeVM mutations, initial-password GET, rDNS PUT, rescue/backup/webhook mutations
reseller.usage.readUsage and spend

Each key allows 120 requests per 60 seconds. Webhook mutations additionally share 10 per 60 seconds per account. Limiters fail closed. Honor Retry-After on 429; vm_busy returns Retry-After: 30.

Create uses JSON idempotencyKey, NOT an Idempotency-Key header. Reuse within the account returns existing VM (200); new create is 201. Persist one key per VM/order and retry same payload/key after transport failure. No general idempotency facility on other mutations.

Actions return 202 {data:{accepted:true,taskId:123}}. taskId can be null; no public task lookup exists. Poll VM detail, rescue GET or backups GET as appropriate. Accepted is not completed. Legacy jobId, vm and credential fields remain. Pending DELETE retains VM fields with accepted/taskId. Create stays 201/200; reset-password/rDNS PUT stay 200.

Statuses: creating, building, active, failed, suspended, delete_requested, deleted. Power/buildState are nullable provider strings. RAM is MiB, disk GiB, dates UTC ISO 8601; backup timestamps Unix seconds. Usage bytes and spend micros/cents are decimal strings; stats counters numbers or null. One USD is 1000000 micros. All authenticated responses have Cache-Control: no-store; spec alone has public, max-age=300.

Endpoint reference

Full bounds and schemas are in the OpenAPI download. Replace IDs/catalog values. No body needed unless shown. Responses illustrate one possible outcome.

GET /account

Scope: reseller.vms.read.

Example
curl -sS "$BASE/account" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "limits": {
      "maxVms": 1,
      "maxVcpu": 1,
      "maxRamMiB": 1,
      "maxDiskGiB": 1,
      "maxIpv4": 1
    },
    "used": {
      "vms": 1,
      "vcpu": 2,
      "ramMiB": 2048,
      "diskGiB": 40,
      "ipv4": 1
    },
    "features": {
      "rescue": false,
      "ipv6": [],
      "backups": false
    },
    "units": {
      "ram": "MiB",
      "disk": "GiB"
    }
  }
}

GET /limits

Scope: reseller.vms.read.

Example
curl -sS "$BASE/limits" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "vcpu": {
      "min": 1,
      "max": 1
    },
    "ramMiB": {
      "min": 1,
      "max": 1,
      "step": 1
    },
    "diskGiB": {
      "min": 1,
      "max": 1
    },
    "ipv4": {
      "min": 1,
      "max": 1
    },
    "units": {
      "ram": "MiB",
      "disk": "GiB"
    }
  }
}

GET /locations

Scope: reseller.vms.read.

Example
curl -sS "$BASE/locations" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": [
    {
      "key": "small",
      "name": "customer-vps-1"
    }
  ]
}

GET /os-templates

Scope: reseller.vms.read.

Example
curl -sS "$BASE/os-templates" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": [
    {
      "id": "cmvmexample001",
      "name": "customer-vps-1",
      "version": "12",
      "group": "Debian",
      "label": "Debian 12"
    }
  ]
}

GET /packages/{key}/os-templates

Scope: reseller.vms.read.

Example
curl -sS "$BASE/packages/small/os-templates" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": [
    {
      "id": "cmvmexample001",
      "name": "customer-vps-1",
      "version": "12",
      "group": "Debian",
      "label": "Debian 12"
    }
  ]
}

GET /packages

Scope: reseller.vms.read.

Example
curl -sS "$BASE/packages" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": [
    {
      "key": "small",
      "vcpu": 2,
      "ramMiB": 2048,
      "diskGiB": 40,
      "units": {
        "ram": "MiB",
        "disk": "GiB"
      }
    }
  ]
}

GET /spend

Scope: reseller.usage.read.

Example
curl -sS "$BASE/spend" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "available": false,
    "reason": "Billing has not started"
  }
}

GET /usage

Scope: reseller.usage.read.

Example
curl -sS "$BASE/usage?month=2026-10" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "month": "2026-10",
    "unit": "hour",
    "timezone": "UTC",
    "vms": [
      {
        "id": "cmvmexample001",
        "vmId": "example",
        "name": "customer-vps-1",
        "package": "example",
        "packageKey": "small",
        "location": "default",
        "vcpu": 2,
        "ramMiB": 2048,
        "diskGiB": 40,
        "ipv4": 1,
        "billableHours": 1,
        "hours": 1,
        "vcpuHours": 1,
        "ramMiBHours": 1,
        "diskGiBHours": 1,
        "rxBytes": "1048576",
        "txBytes": "1048576"
      }
    ]
  }
}

POST /vms/{id}/backups/{backupId}/restore

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/backups/1-3-1700000000/restore" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123,
    "jobId": 123
  }
}

GET /vms/{id}/backups

Scope: reseller.vms.read.

Example
curl -sS "$BASE/vms/cmvmexample001/backups" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "backups": [
      {
        "id": "cmvmexample001",
        "disk": 1,
        "timestamp": 1,
        "type": "example",
        "size": 1
      }
    ],
    "page": 1,
    "lastPage": 1
  }
}

POST /vms/{id}/backups

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/backups" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123,
    "jobId": 123
  }
}

GET /vms/{id}/initial-password

Scope: reseller.vms.write.

Example
curl -sS "$BASE/vms/cmvmexample001/initial-password" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "password": "example-secret"
  }
}

POST /vms/{id}/ipv4

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/ipv4" -H "Authorization: Bearer $RESELLER_KEY" -H 'Content-Type: application/json' -d '{"quantity":1}'

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123
  }
}

POST /vms/{id}/power

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/power" -H "Authorization: Bearer $RESELLER_KEY" -H 'Content-Type: application/json' -d '{"action":"start"}'

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123
  }
}

GET /vms/{id}/rdns

Scope: reseller.vms.read.

Example
curl -sS "$BASE/vms/cmvmexample001/rdns" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": [
    {
      "ip": "203.0.113.10",
      "hostname": "vps1.example.com",
      "status": "none"
    }
  ]
}

PUT /vms/{id}/rdns

Scope: reseller.vms.write.

Example
curl -sS -X PUT "$BASE/vms/cmvmexample001/rdns" -H "Authorization: Bearer $RESELLER_KEY" -H 'Content-Type: application/json' -d '{"ip":"203.0.113.10","hostname":"vps1.example.com"}'

HTTP 200:

Example
{
  "data": {
    "ip": "203.0.113.10",
    "hostname": "vps1.example.com",
    "status": "pending"
  }
}

POST /vms/{id}/rebuild

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/rebuild" -H "Authorization: Bearer $RESELLER_KEY" -H 'Content-Type: application/json' -d '{"osTemplateId":14}'

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123
  }
}

POST /vms/{id}/rescue

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/rescue" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123,
    "password": "example-secret"
  }
}

DELETE /vms/{id}/rescue

Scope: reseller.vms.write.

Example
curl -sS -X DELETE "$BASE/vms/cmvmexample001/rescue" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123
  }
}

GET /vms/{id}/rescue

Scope: reseller.vms.read.

Example
curl -sS "$BASE/vms/cmvmexample001/rescue" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "enabled": false
  }
}

POST /vms/{id}/reset-password

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/reset-password" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "password": "example-secret"
  }
}

POST /vms/{id}/resize

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/resize" -H "Authorization: Bearer $RESELLER_KEY" -H 'Content-Type: application/json' -d '{"vcpu":4,"restart":true}'

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123,
    "vm": {
      "id": "cmvmexample001",
      "name": "customer-vps-1",
      "hostname": "vps1.example.com",
      "initialPasswordAvailable": false,
      "loginMethod": "password",
      "packageKey": "small",
      "location": "default",
      "vcpu": 2,
      "ramMiB": 2048,
      "diskGiB": 40,
      "pendingIpv4": 1,
      "reconcileNeeded": false,
      "ipv4Count": 1,
      "status": "active",
      "endUserRef": "example",
      "ips": [
        "203.0.113.10"
      ],
      "ipv6": [],
      "power": "running",
      "buildState": "complete",
      "createdAt": "2026-10-24T10:00:00.000Z",
      "activeAt": "2026-10-24T10:00:00.000Z",
      "deletedAt": null
    }
  }
}

GET /vms/{id}

Scope: reseller.vms.read.

Example
curl -sS "$BASE/vms/cmvmexample001" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "id": "cmvmexample001",
    "name": "customer-vps-1",
    "hostname": "vps1.example.com",
    "initialPasswordAvailable": false,
    "loginMethod": "password",
    "packageKey": "small",
    "location": "default",
    "vcpu": 2,
    "ramMiB": 2048,
    "diskGiB": 40,
    "pendingIpv4": 1,
    "reconcileNeeded": false,
    "ipv4Count": 1,
    "status": "active",
    "endUserRef": "example",
    "ips": [
      "203.0.113.10"
    ],
    "ipv6": [],
    "power": "running",
    "buildState": "complete",
    "createdAt": "2026-10-24T10:00:00.000Z",
    "activeAt": "2026-10-24T10:00:00.000Z",
    "deletedAt": null
  }
}

DELETE /vms/{id}

Scope: reseller.vms.write.

Example
curl -sS -X DELETE "$BASE/vms/cmvmexample001" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "id": "cmvmexample001",
    "name": "customer-vps-1",
    "hostname": "vps1.example.com",
    "initialPasswordAvailable": false,
    "loginMethod": "password",
    "packageKey": "small",
    "location": "default",
    "vcpu": 2,
    "ramMiB": 2048,
    "diskGiB": 40,
    "pendingIpv4": 1,
    "reconcileNeeded": false,
    "ipv4Count": 1,
    "status": "active",
    "endUserRef": "example",
    "ips": [
      "203.0.113.10"
    ],
    "ipv6": [],
    "power": "running",
    "buildState": "complete",
    "createdAt": "2026-10-24T10:00:00.000Z",
    "activeAt": "2026-10-24T10:00:00.000Z",
    "deletedAt": null
  }
}

GET /vms/{id}/stats

Scope: reseller.vms.read.

Example
curl -sS "$BASE/vms/cmvmexample001/stats" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "power": "running",
    "cpuPercent": 1,
    "memory": {
      "totalMiB": 1,
      "usedMiB": 1
    },
    "traffic": {
      "periodStart": "example",
      "periodEnd": "example",
      "rxBytes": 1,
      "txBytes": 1
    }
  }
}

POST /vms/{id}/suspend

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/suspend" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123
  }
}

POST /vms/{id}/unsuspend

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms/cmvmexample001/unsuspend" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 202:

Example
{
  "data": {
    "accepted": true,
    "taskId": 123
  }
}

GET /vms

Scope: reseller.vms.read.

Example
curl -sS "$BASE/vms" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": [
    {
      "id": "cmvmexample001",
      "name": "customer-vps-1",
      "hostname": "vps1.example.com",
      "initialPasswordAvailable": false,
      "loginMethod": "password",
      "packageKey": "small",
      "location": "default",
      "vcpu": 2,
      "ramMiB": 2048,
      "diskGiB": 40,
      "pendingIpv4": 1,
      "reconcileNeeded": false,
      "ipv4Count": 1,
      "status": "active",
      "endUserRef": "example",
      "ips": [
        "203.0.113.10"
      ],
      "ipv6": [],
      "power": "running",
      "buildState": "complete",
      "createdAt": "2026-10-24T10:00:00.000Z",
      "activeAt": "2026-10-24T10:00:00.000Z",
      "deletedAt": null
    }
  ]
}

POST /vms

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/vms" -H "Authorization: Bearer $RESELLER_KEY" -H 'Content-Type: application/json' -d '{"name":"customer-vps-1","hostname":"vps1.example.com","location":"default","packageKey":"small","osTemplateId":14,"idempotencyKey":"order-20261024-0042","ipv4":1,"endUser":{"ref":"customer-42","email":"customer@example.com","name":"Example Customer"}}'

HTTP 201:

Example
{
  "data": {
    "id": "cmvmexample001",
    "name": "customer-vps-1",
    "hostname": "vps1.example.com",
    "initialPasswordAvailable": false,
    "loginMethod": "password",
    "packageKey": "small",
    "location": "default",
    "vcpu": 2,
    "ramMiB": 2048,
    "diskGiB": 40,
    "pendingIpv4": 1,
    "reconcileNeeded": false,
    "ipv4Count": 1,
    "status": "building",
    "endUserRef": "example",
    "ips": [
      "203.0.113.10"
    ],
    "ipv6": [],
    "power": "running",
    "buildState": "complete",
    "createdAt": "2026-10-24T10:00:00.000Z",
    "activeAt": "2026-10-24T10:00:00.000Z",
    "deletedAt": null
  }
}

DELETE /webhooks/{id}

Scope: reseller.vms.write.

Example
curl -sS -X DELETE "$BASE/webhooks/cmvmexample001" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": {
    "deleted": true
  }
}

GET /webhooks

Scope: reseller.vms.read.

Example
curl -sS "$BASE/webhooks" -H "Authorization: Bearer $RESELLER_KEY"

HTTP 200:

Example
{
  "data": [
    {
      "id": "cmvmexample001",
      "url": "https://hooks.example.com/corepanel",
      "events": [
        "vm.active"
      ],
      "enabled": false,
      "createdAt": "2026-10-24T10:00:00.000Z",
      "deliveries": [
        {
          "id": "cmvmexample001",
          "event": "example",
          "status": "pending",
          "attempts": 1,
          "lastStatusCode": 1,
          "createdAt": "2026-10-24T10:00:00.000Z",
          "deliveredAt": "2026-10-24T10:00:00.000Z"
        }
      ]
    }
  ]
}

POST /webhooks

Scope: reseller.vms.write.

Example
curl -sS -X POST "$BASE/webhooks" -H "Authorization: Bearer $RESELLER_KEY" -H 'Content-Type: application/json' -d '{"url":"https://hooks.example.com/corepanel","events":["vm.active"]}'

HTTP 201:

Example
{
  "data": {
    "id": "cmvmexample001",
    "url": "https://hooks.example.com/corepanel",
    "events": [
      "vm.active"
    ],
    "enabled": false,
    "createdAt": "2026-10-24T10:00:00.000Z",
    "deliveries": [
      {
        "id": "cmvmexample001",
        "event": "example",
        "status": "pending",
        "attempts": 1,
        "lastStatusCode": 1,
        "createdAt": "2026-10-24T10:00:00.000Z",
        "deliveredAt": "2026-10-24T10:00:00.000Z"
      }
    ],
    "secret": "example-hook-secret"
  }
}

GET /openapi.json

Example
curl -sS "$BASE/openapi.json"

HTTP 200: complete unwrapped OpenAPI document.

Create and query constraints

Create with either packageKey or all of vcpu, ramMiB, diskGiB, never both. Custom bounds: vCPU 1–32, RAM 1024–262144 MiB in steps of 1024, disk 10–1024 GiB. ipv4 is 1–8 (default 1); omit ipv6 for the location default. sshKeys allows up to five trimmed, deduplicated OpenSSH public keys (ed25519, RSA or ECDSA), at most 8192 UTF-8 bytes per key. SSH-key VMs have no initial password.

GET /vms accepts endUserRef; backup lists accept positive integer page (default 1) and return page/lastPage. Usage requires month=YYYY-MM (UTC). Power accepts start, stop, restart, poweroff. See VM lifecycle, webhooks and errors for operation semantics.