API: servers
Cloud VPS and dedicated servers are both “services”, but they sit behind different infrastructure — cloud on our own Proxmox clusters, dedicated through our provisioning platform. The paths differ accordingly.
Listing your servers
curl https://my.server.express/api/v1/cloud \
-H "Authorization: Bearer $SE_TOKEN"
Returns your cloud services, newest first, each with its product. /dedicated does the same for dedicated servers. Both need services:read — see authentication and scopes if your token doesn’t have it.
For one service:
GET /cloud/:id
GET /dedicated/:id
The id is the service ID from the list — it’s the identifier for everything below.
Cloud VPS
Current state
GET /cloud/:id/servers # VMs belonging to this service
GET /cloud/:id/:vmid # live status of one VM
GET /cloud/:id/network # IP assignments
All services:read. The vmid comes from /cloud/:id/servers.
Metrics
curl "https://my.server.express/api/v1/cloud/$ID/stats?timeframe=day" \
-H "Authorization: Bearer $SE_TOKEN"
timeframe is one of hour, day, week, month, defaulting to hour. Anything else falls back to hour rather than erroring.
You get current state plus a usage series for CPU, memory, disk and network. Requires services:stats.
The response also carries an estimated power draw and carbon figure, derived from vCPU load, datacenter PUE and the grid intensity of the country the node sits in. It’s a decent estimate for reporting. It is not metered, and it isn’t what you’re billed on.
Power
curl -X POST https://my.server.express/api/v1/cloud/$ID/$VMID \
-H "Authorization: Bearer $SE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"reboot"}'
action is start, stop or reboot. Requires services:power.
stop is a hard power-off, not a graceful shutdown. Treat it like pulling the plug, because that’s what it is.
The response returns the hypervisor task ID:
{ "success": true, "data": { "upid": "UPID:node:..." } }
That’s a handle on an async job. The call returning doesn’t mean the VM has finished booting.
Reinstall
curl -X POST https://my.server.express/api/v1/cloud/$ID/reinstall \
-H "Authorization: Bearer $SE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"os":"ubuntu-24.04"}'
os is a template slug — fetch the valid list from GET /cloud/templates. Requires services:reinstall.
This wipes the disk. There is no confirmation step and no undo. See Reinstalling your server for what survives (your IPs and rDNS) and what doesn’t (everything else).
You’ll get 409 if a reinstall is already running, and 422 if the VM was never provisioned.
Credentials
GET /cloud/:id/credentials
Returns the current root credentials. Requires services:rescue.
Handle the response like the secret it is — don’t log it, don’t put it in CI output.
Dedicated servers
GET /dedicated/:id/overview # spec and status summary
GET /dedicated/:id/network # IPs and rDNS
GET /dedicated/:id/metadata # hardware detail
GET /dedicated/:id/activity # recent actions
All services:read.
Power
curl -X POST https://my.server.express/api/v1/dedicated/$ID/power \
-H "Authorization: Bearer $SE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"reset"}'
Four actions here, not three: start, stop, reboot, reset. reset is the physical reset line — use it when the OS has stopped answering and reboot won’t take. Requires services:power.
Rescue mode
curl -X POST https://my.server.express/api/v1/dedicated/$ID/rescue \
-H "Authorization: Bearer $SE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"osId":"rescue-linux"}'
Boots a rescue environment instead of the installed OS, so you can mount the disk and fix whatever broke. Requires services:rescue.
Reinstall
curl -X POST https://my.server.express/api/v1/dedicated/$ID/reinstall \
-H "Authorization: Bearer $SE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"osId":"ubuntu-24.04","hostname":"web-01"}'
Both osId and hostname are required. Valid OS IDs come from GET /dedicated/:id/profiles. Requires services:reinstall. Same warning as above — the disk goes.
Cancelling
curl -X POST https://my.server.express/api/v1/cloud/$ID/cancel \
-H "Authorization: Bearer $SE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason":"project finished","immediate":false}'
/dedicated/:id/cancel works the same way. Requires services:cancel.
immediate is the field that matters:
false(the default) schedules cancellation for the end of your paid period. The server keeps running until then.trueterminates it now. The service stops and the data goes.
Defaulting to false is deliberate. If you’re passing immediate from a variable, make sure you know what’s in it.
Billing carries on until the period ends, which is the invoice side of the same thing.
reason is optional and shows up in our records. It’s genuinely read — if something didn’t work, saying so here is useful.
A worked example
Reboot every running cloud VPS on the account:
#!/usr/bin/env bash
set -euo pipefail
API="https://my.server.express/api/v1"
AUTH="Authorization: Bearer $SE_TOKEN"
curl -sf "$API/cloud" -H "$AUTH" | jq -r '.data[].id' | while read -r id; do
curl -sf "$API/cloud/$id/servers" -H "$AUTH" | jq -r '.data[].vmid' | while read -r vmid; do
echo "rebooting $id/$vmid"
curl -sf -X POST "$API/cloud/$id/$vmid" -H "$AUTH" \
-H 'Content-Type: application/json' -d '{"action":"reboot"}' | jq -r '.data.upid'
done
done
That needs a token with services:read and services:power — and nothing else. Which is the whole argument for scopes.
Last updated Invalid Date. Something wrong or missing? Tell us and we'll fix it.