The CheapServ API is a small JSON API for the things you automate: listing plans and locations, ordering servers from your balance, reading your servers, and opening and tracking top-ups. It is the same interface the dashboard uses, with no extra features hidden behind it.
- Base URL
https://cheapserv.com/v1- Format
- JSON request bodies and responses, UTF-8
- Authentication
Authorization: Bearer cs_…- Rate limit
- 120 requests per minute per key
Authentication
Generate a key under Account → API. The full key, prefixed cs_, is shown once; store it in your secret manager. Send it on every authenticated request in the Authorization header:
curl https://cheapserv.com/v1/account \
-H "Authorization: Bearer cs_0038063…"
Keys carry the full rights of the account. Revoke a leaked key immediately from the dashboard; revocation takes effect on the next request. GET /v1/plans and GET /v1/locations are public and need no key.
Rate limits
Each key may make 120 requests per minute. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining; when the limit is exhausted the API answers 429 with the error code rate_limited. Poll a top-up no more often than every 10 seconds — the state changes only on network confirmations.
Errors
Errors are returned as a JSON object with a stable code and a human-readable message:
{"error":{"code":"validation","message":"The hostname is invalid."}}
| HTTP | Code | Meaning |
|---|---|---|
| 400 | validation | A field is missing or invalid; the message names it (also: a top-up below $25 or above $5,000, or an unsupported coin) |
| 401 | unauthorized | Missing, unknown or revoked key |
| 402 | insufficient_balance | The balance does not cover the order; see POST /v1/servers |
| 404 | not_found | Unknown endpoint, or an object that is not yours |
| 429 | rate_limited | More than 120 requests in the last minute, or too many deposit addresses opened in a short while |
| 503 | orchestrator_down | The payment network did not answer; nothing was created, retry in a moment |
GET /v1/plans
Public. Returns every plan grouped by product, with live stock. Use the slug when ordering.
curl https://cheapserv.com/v1/plans
{
"vps": [
{"slug":"vps-4","name":"VPS-4","monthly_usd":6.99,"stock":"in_stock",
"specs":{"vcpu":"4","ram":"8 GB","nvme":"160 GB","traffic":"12 TB"}},
{"slug":"hf-2","name":"HF-2","monthly_usd":12.39,"stock":"low",
"specs":{"cores":"2","ram":"8 GB","nvme":"120 GB","traffic":"8 TB"}}
],
"dedicated": [ {"slug":"ds-9950x","name":"DS-9950X","monthly_usd":239, "stock":"in_stock","specs":{"cpu":"AMD Ryzen 9 9950X", "ram":"192 GB","storage":"2× 4 TB NVMe Gen4","net":"1 Gbps unmetered"}} ],
"gpu": [ {"slug":"h100-sxm","name":"H100 SXM","monthly_usd":979,"stock":"in_stock","specs":{"vram":"80 GB HBM3","vcpu":"32","ram":"256 GB","nvme":"2 TB","net":"10 Gbps"}} ],
"rdp": [ {"slug":"rdp-4","name":"RDP-4","monthly_usd":15.19,"stock":"in_stock","specs":{"vcpu":"4","ram":"8 GB","nvme":"160 GB","os":"Windows Server 2022/2025"}} ]
}
stock is in_stock, low (four units or fewer) or sold_out. Ordering a sold-out plan fails with a validation error. The VPS group contains all three lines; slugs starting with hf- are High-frequency and st- are Storage plans.
GET /v1/locations
Public. Lists the six sites and the products each one can host. Plan availability follows the product list: vps_hf and vps_storage are listed separately from vps.
curl https://cheapserv.com/v1/locations
[
{"code":"fra","city":"Frankfurt","country":"DE","hub":true,
"products":["vps","vps_hf","vps_storage","dedicated","gpu","rdp"]},
{"code":"hel","city":"Helsinki","country":"FI","hub":false,
"products":["vps","vps_hf","vps_storage","dedicated","rdp"]}
]
GET /v1/account
curl https://cheapserv.com/v1/account \
-H "Authorization: Bearer $CS_KEY"
{"email":"[email protected]","balance_usd":142.50,"created_at":"2026-09-05T14:40:12Z"}
GET /v1/servers
Returns your servers, newest first. Each server object carries the addresses assigned at provisioning and the next renewal date.
curl https://cheapserv.com/v1/servers \
-H "Authorization: Bearer $CS_KEY"
[
{"id":1041,"hostname":"web-01","product":"vps","plan":"vps-4","plan_name":"VPS-4",
"location":"ams","image":"debian-13-12","ipv4":"198.51.100.86","ipv6":"2001:db8:2:411::1",
"status":"active","rescue":false,"backups":false,"monthly_usd":6.99,
"renews_at":"2026-10-05 14:41:03","created_at":"2026-09-05 14:41:03"}
]
status is provisioning (about 60 seconds after payment), active, stopped, rebooting, reinstalling, starting, stopping, suspended or cancelled.
POST /v1/servers
Creates an order and pays it from your prepaid balance. When the balance covers the plan price, the servers are created at once and provisioning starts; they are online within about 60 seconds. When it does not, nothing is created and the API answers 402 with the missing amount — top up first, then send the order again.
| Field | Type | Required | Notes |
|---|---|---|---|
product | string | yes | vps, dedicated, gpu or rdp |
plan | string | yes | Plan slug from /v1/plans |
location | string | yes | fra, ams, hel, nyc, lax or sin |
image | string | no | Image slug; defaults to the first image of the product |
hostname | string | no | Lowercase letters, digits, dashes, dots; max 63 characters; generated if omitted |
qty | integer | no | 1 to 10 for VPS and RDP, always 1 otherwise |
curl -X POST https://cheapserv.com/v1/servers \
-H "Authorization: Bearer $CS_KEY" \
-H "Content-Type: application/json" \
-d '{"product":"vps","plan":"vps-4","location":"fra",
"image":"ubuntu-24-04-22-04","hostname":"web-01","qty":1}'
HTTP/2 201
{"order_id":1041,"paid":true,
"servers":[
{"id":1041,"hostname":"web-01","product":"vps","plan":"vps-4","plan_name":"VPS-4",
"location":"fra","image":"ubuntu-24-04-22-04","ipv4":"198.51.100.49","ipv6":"2001:db8:1:411::1",
"status":"provisioning","rescue":false,"backups":false,"monthly_usd":6.99,
"renews_at":"2026-10-05 14:41:03","created_at":"2026-09-05 14:41:03"}
]}
When the balance is short:
HTTP/2 402
{"error":{"code":"insufficient_balance","message":"Your balance does not cover this order. Top up first."},
"balance_usd":4.20,"total_usd":6.99,"missing_usd":2.79,
"topup_url":"https://cheapserv.com/account/topup"}
A plan that is not offered in the chosen location, a sold-out plan or an invalid hostname returns 400 validation. With qty above 1, one server object is returned per machine, with hostnames suffixed -1, -2 and so on.
Slugs
Plan slugs are the plan name in lowercase with spaces replaced by dashes and × by x: vps-4, hf-2, st-1, ds-9950x, rtx-5090, h100-sxm, 8x-h100-sxm, rdp-4, rdp-gpu. Image slugs are the image name and version in lowercase with every run of non-alphanumeric characters replaced by a dash: ubuntu-24-04-22-04, debian-13-12, rocky-linux-10-9, windows-server-2022-2025.
GET /v1/topups
Lists your top-ups, newest first, as top-up objects (see below).
curl https://cheapserv.com/v1/topups \
-H "Authorization: Bearer $CS_KEY"
POST /v1/topups
Opens a top-up and returns its deposit details: a unique address, the exact crypto amount and a 30-minute validity. Amounts are in USD, between $25 and $5,000. Coin codes: BTC, ETH, XMR, USDTTRC (Tether on TRC-20) and USDT (Tether on ERC-20). Opening a second top-up with the same coin and amount while the first address is still valid returns the existing one instead of a new address.
curl -X POST https://cheapserv.com/v1/topups \
-H "Authorization: Bearer $CS_KEY" \
-H "Content-Type: application/json" \
-d '{"amount_usd":50,"coin":"USDTTRC"}'
HTTP/2 201
{"ref":"cs-k7m2qp4xh9b1zt3v6nwd","amount_usd":50,"bonus_usd":0,"coin":"USDTTRC","status":"pending",
"deposit_address":"TX3…","deposit_amount":"50.01","deposit_network":"TRX","deposit_tag":null,
"received":null,"missing":null,"txid":null,
"expires_at":"2026-09-05 15:11:03","paid_at":null,"created_at":"2026-09-05 14:41:03",
"url":"https://cheapserv.com/account/topup/cs-k7m2qp4xh9b1zt3v6nwd"}
Send exactly deposit_amount in coin to deposit_address on deposit_network before expires_at. An amount below $25 or above $5,000, or an unsupported coin, returns 400 validation; too many addresses opened in a short while returns 429 rate_limited; if the payment network does not answer, 503 orchestrator_down and nothing was created.
GET /v1/topups/{ref}
Returns one top-up and refreshes its status from the payment network. status is pending (awaiting deposit), confirming, underpaid (received and missing then carry the crypto amounts; send missing to the same address), completed (the balance is credited), expired, cancelled or error. An expired top-up cannot be revived: open a new one instead.
curl https://cheapserv.com/v1/topups/cs-k7m2qp4xh9b1zt3v6nwd \
-H "Authorization: Bearer $CS_KEY"
{"ref":"cs-k7m2qp4xh9b1zt3v6nwd","amount_usd":50,"bonus_usd":0,"coin":"USDTTRC","status":"completed",
"deposit_address":"TX3…","deposit_amount":"50.01","deposit_network":"TRX","deposit_tag":null,
"received":null,"missing":null,"txid":"7c1e…",
"expires_at":"2026-09-05 15:11:03","paid_at":"2026-09-05 14:52:40","created_at":"2026-09-05 14:41:03",
"url":"https://cheapserv.com/account/topup/cs-k7m2qp4xh9b1zt3v6nwd"}
Example: top up, wait for the credit, then order
#!/bin/sh
set -e
API=https://cheapserv.com/v1
ref=$(curl -sf -X POST "$API/topups" \
-H "Authorization: Bearer $CS_KEY" -H "Content-Type: application/json" \
-d '{"amount_usd":50,"coin":"USDTTRC"}' | jq -r .ref)
echo "top-up $ref — send the deposit shown at $API/topups/$ref"
while :; do
st=$(curl -sf "$API/topups/$ref" -H "Authorization: Bearer $CS_KEY" | jq -r .status)
[ "$st" = completed ] && break
[ "$st" = expired ] && { echo expired; exit 1; }
sleep 10
done
curl -sf -X POST "$API/servers" \
-H "Authorization: Bearer $CS_KEY" -H "Content-Type: application/json" \
-d '{"product":"vps","plan":"hf-2","location":"nyc","hostname":"db-01"}' | jq '.servers[]'
Versioning
The path prefix /v1 is the version. Fields are only ever added to responses, never removed or renamed, within a version; ignore fields you do not know. Breaking changes will ship as /v2 with both versions running side by side for at least six months, announced on Status and by e-mail to every account holding an API key.
Something missing or wrong on this page? Open a ticket and tell us.