Docs / API Reference
REST API reference
Authenticate with an API key and manage your Piedmont Hosting servers, firewall rules, snapshots and backups over the REST API.
API Overview
The Piedmont Hosting REST API lets you script day-to-day operations on your existing VPS servers: power actions, cloud firewall rules, snapshots and backups. It covers VPS services only, and it can't create, resize, reinstall or delete servers — do those in the portal.
Base URL
https://vps.piedmonthosting.com/api/v1
Response Format
All responses are JSON. Most successful responses wrap their data in a named object — for example {"server": {…}} or {"servers": […]} — and status values are lowercase. Times are ISO 8601 in UTC. Errors return an error field with a human-readable message.
{
"server": {
"id": "clx0abc123def456",
"name": "my-server (2vCPU/4GB/40GB)",
"hostname": "my-server",
"status": "active",
"os": "ubuntu24",
"vcpus": 2,
"memory_mb": 4096,
"disk_mb": 40960,
"bandwidth_mbps": 250,
"ip_address": "203.0.113.40",
"private_ip": "10.10.50.40",
"monthly_price": 19,
"created_at": "2026-10-01T12:00:00.000Z",
"updated_at": "2026-10-01T12:05:00.000Z"
}
}{
"error": "Server not found"
}Status Codes
| Code | Meaning |
|---|---|
| 200, 201, 202 | Success. 201 means something was created; 202 means the job was started and finishes in the background. |
| 400 | The request was invalid — the error says what to fix |
| 401 | Missing, invalid, revoked or expired API key |
| 403 | The key doesn't have the permission this action needs (a manual backup also returns 403 while backups aren't enabled) |
| 404 | No such server on your account — or, for most changes, the server isn't active |
| 409 | A limit was reached, or something is already in progress |
| 500 | Something went wrong on our side |
Authentication
API requests are authenticated with API keys. Create one on the API Keys page. A key looks like ph_live_ followed by 32 hex characters and is shown only once, so copy it when you create it. You can have up to 10 active keys.
Using Your API Key
Include your API key in the Authorization header of every request:
Authorization: Bearer ph_live_your_api_key_here
curl -H "Authorization: Bearer ph_live_your_api_key_here" \ https://vps.piedmonthosting.com/api/v1/servers
Permissions
Every key can call the read (GET) endpoints. A Read Only key can do only that; to make changes, give the key the matching permission — or choose Full Access, which allows everything. A request outside a key's permissions returns 403 with {"error": "Insufficient permissions"}.
| Permission | API value | Allows |
|---|---|---|
| Full Access | * | Everything below, plus creating and revoking API keys over the API |
| Read Only | read | Read endpoints only |
| Power | power | Power actions |
| Firewall | firewall | Adding, changing and deleting firewall rules, and applying presets |
| Snapshots | snapshots | Creating, restoring and deleting snapshots |
| Backups | backups | Manual backups, restores and backup settings — including turning the paid backup add-on on or off |
Managing Keys over the API
Creating or revoking a key needs a Full Access key (or a signed-in portal session); any other key gets 403. Listing keys works with any key.
curl -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/api-keys
Returns {"api_keys": […]} — your active keys with their name, prefix, permissions, last use and expiry. The keys themselves are never shown again.
curl -X POST -H "Authorization: Bearer ph_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Backup script",
"permissions": ["backups"],
"expires_in_days": 90
}' \
https://vps.piedmonthosting.com/api/v1/api-keysname is required (up to 100 characters). permissions is a list of the API values above and defaults to ["*"] (Full Access) if you leave it out, so list only what the key needs. expires_in_days is optional; keys created on the API Keys page don't expire. Returns 201 with the key details in api_key and the key itself in key — the only time it's shown. An eleventh active key returns 400.
curl -X DELETE -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/api-keys/KEY_ID
Revokes the key immediately and returns {"message": "API key revoked"}.
Server Endpoints
In the paths below, SERVER_ID is a server's id from GET /api/v1/servers — it's also the last part of the server's page address in the portal (/services/SERVER_ID). Game servers and web hosting aren't available through the API and return 404.
List All Servers
curl -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers
Returns {"servers": […]} — every VPS on your account that hasn't been terminated, newest first. Each server has id, name, hostname, status (lowercase, e.g. active or suspended), os, vcpus, memory_mb, disk_mb, bandwidth_mbps (the port-speed cap), ip_address (public IPv4), private_ip (the server's internal 10.10.50.x address, not its VPC address), monthly_price, created_at and updated_at.
Get Server Details
curl -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID
Returns {"server": {…}} with the same fields — see the example under API Overview.
Get Server Power Status
curl -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/status
Returns {"server_id", "vm_name", "state"}, where state is the hypervisor's live state — for example running, shut off or paused (unknown if it can't be read).
Power Actions
curl -X POST -H "Authorization: Bearer ph_live_xxx" \
-H "Content-Type: application/json" \
-d '{"action": "reboot"}' \
https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/powerValid actions: start, shutdown, reboot, reset. shutdown and reboot ask the operating system to shut down or restart cleanly; reset is an immediate hard restart. Requires the Power permission. The command is sent right away and the response — {"action", "server_id", "message"} — doesn't wait for it to finish; check /status to see the result.
Firewall Endpoints
List Firewall Rules
curl -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/firewall
Returns {"rules": […], "presets": […]}. Each rule has id, direction, protocol, port_range, source_cidr, action, description, priority, enabled and synced.
Add Firewall Rule
curl -X POST -H "Authorization: Bearer ph_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"direction": "INBOUND",
"protocol": "TCP",
"port_range": "443",
"source_cidr": "0.0.0.0/0",
"action": "ACCEPT",
"description": "Allow HTTPS"
}' \
https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/firewall| Field | Values | Default |
|---|---|---|
direction | INBOUND or OUTBOUND | INBOUND |
protocol | TCP, UDP, ICMP or ANY | TCP |
port_range | A port ("443") or a range ("1000-2000"), as a string. Required for TCP and UDP rules — a TCP or UDP rule without one isn't applied. Leave it out for ICMP; for ANY, leaving it out matches all traffic from source_cidr. | — |
source_cidr | Who the rule applies to: 0.0.0.0/0 for anyone, or an IPv4 address or range such as 203.0.113.0/24 | 0.0.0.0/0 |
action | ACCEPT or DROP | ACCEPT |
description | Your own label, shown in the portal | — |
priority | Lower numbers are checked first | 100 |
Returns 201 with the new rule in {"rule": {…}}. The server must be active, each server can have up to 50 rules (409 after that), and the Firewall permission is required.
Update Firewall Rule
curl -X PUT -H "Authorization: Bearer ph_live_xxx" \
-H "Content-Type: application/json" \
-d '{"enabled": false}' \
https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/firewall/RULE_IDSend any of direction, protocol, port_range, source_cidr, action, description, priority and enabled, in the same formats as when adding a rule. Returns the updated rule.
Delete Firewall Rule
curl -X DELETE -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/firewall/RULE_ID
Apply Firewall Preset
curl -X POST -H "Authorization: Bearer ph_live_xxx" \
-H "Content-Type: application/json" \
-d '{"preset": "web-server"}' \
https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/firewall/presetAvailable presets: web-server (Web Server), game-server (Game Server), proxmox-node (Proxmox VE Node), ssh-only (SSH Only), all-open (All Open). Applying a preset deletes every existing rule on the server — including rules the App Marketplace added for your apps — and replaces them with the preset's rules. Returns {"message", "rules_count"}.
Snapshot Endpoints
List Snapshots
curl -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/snapshots
Returns {"snapshots": […], "limit": 3, "used": 1}. Each snapshot has id, name, status (creating, available, restoring or failed), size_bytes, created_at and completed_at. GET /api/v1/servers/:id/snapshots/:snapshotId returns a single snapshot.
Create Snapshot
curl -X POST -H "Authorization: Bearer ph_live_xxx" \
-H "Content-Type: application/json" \
-d '{"name": "before-upgrade"}' \
https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/snapshotsReturns 202 with {"snapshot": {"id", "name", "status": "creating"}}; poll the list until it's available. Names keep only letters, numbers, - and _ (other characters are removed) and are cut to 64 characters. The server must be active; creating one more snapshot than the limit returns 409.
Restore Snapshot
curl -X POST -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/snapshots/SNAPSHOT_ID/restore
Returns 202. The snapshot must be available and the server active.
Delete Snapshot
curl -X DELETE -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/snapshots/SNAPSHOT_ID
A snapshot that's still being created or restored can't be deleted (409). All snapshot changes require the Snapshots permission.
Backup Endpoints
These endpoints manage the paid automated backups add-on. All changes require the Backups permission.
List Backups
curl -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/backups
Returns {"backups": […], "config": {…}} — up to the 30 most recent backups that haven't expired (status is running, completed or failed) and the current backup settings.
Start a Manual Backup
curl -X POST -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/backups
Starts a backup immediately and returns 202. Backups must be enabled first (403 otherwise), and only one can run at a time (409).
Configure Backups
curl -X PUT -H "Authorization: Bearer ph_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"retention_days": 14,
"schedule_hour_utc": 4
}' \
https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/backup-configEvery field is optional. retention_days (1–30, default 7) sets how long backups are kept, and schedule_hour_utc (0–23, default 3) sets the hour the daily backup runs. Setting enabled to true adds the automated-backup add-on (10% of the server's price) to your subscription, prorated; false removes it. GET /api/v1/servers/:id/backup-config returns the current settings.
Restore Backup
curl -X POST -H "Authorization: Bearer ph_live_xxx" \ https://vps.piedmonthosting.com/api/v1/servers/SERVER_ID/backups/BACKUP_ID/restore
Returns 202. The backup must be completed, and a restore can't start while a backup is running (409).