API documentation
Your agent can host itself
The whole platform is an email address and a REST API away: register, top up with crypto, deploy a fleet, destroy it when done. No human in the loop required — this page tells your agent everything it needs.
1. Point it at one URL
Give your agent /llms.txt — a plain-text version of this page that LLM tools fetch and follow out of the box.
2. Or paste the context
Copy the full instruction block below straight into your agent's system prompt or tool description. It is self-contained.
3. It does the rest
Register → check balance → deploy → poll until ACTIVE → SSH as root → destroy. Hourly billing means experiments cost cents.
# CryptoVPS — API guide for AI agents
> CryptoVPS deploys cloud VPS servers (NVMe, dedicated IPv4, root SSH) on top-tier
> providers, paid by the hour from a crypto-funded balance. No KYC: an email
> address is the whole identity. REST API over JSON.
>
> Base URL: https://api.cryptovps.example
> Human docs: /docs · This file: /llms.txt
## Happy path (deploy one server)
1. POST /auth/register {"email":"...","password":"min 8 chars"}
-> 201 {"accessToken":"<jwt>","user":{...}} (or POST /auth/login if registered)
2. Send "Authorization: Bearer <accessToken>" on every request below.
3. GET /billing -> {"balance":"10.00","hourlySpend":"0"}
Balance must cover >= 1 hour of the chosen plan, else POST /servers returns 402.
4. POST /servers {"label":"my-bot","planId":"vc2-1c-1gb","regionId":"ams"}
-> 202 {"server":{"id":"...","status":"PROVISIONING","ipv4":null,...}}
5. Poll GET /servers/<id> every ~5s until "status":"ACTIVE" (typically ~60s).
Then "ipv4" is set — SSH as root is available.
6. DELETE /servers/<id> -> 202. Billing for it stops the same hour.
## Endpoints
POST /auth/register
Create an account. Email + password is all that is needed.
body: {"email":"[email protected]","password":"min-8-chars"}
returns: 201 {"accessToken":"<jwt>","user":{"id","email","balance"}}
POST /auth/login
Get a fresh access token (expires in 15 minutes).
body: {"email":"...","password":"..."}
returns: 200 {"accessToken":"<jwt>","user":{...}}
GET /auth/me (auth)
Whoami: id, email and current balance.
returns: 200 {"user":{"id","email","balance":"9.96"}}
GET /billing (auth)
Balance and total hourly spend across active servers.
returns: 200 {"balance":"9.96","hourlySpend":"0.012"}
GET /servers (auth)
List all non-destroyed servers.
returns: 200 {"servers":[{"id","label","status","region","plan","ipv4","hourlyPrice","createdAt"}]}
GET /servers/:id (auth)
One server. Poll this every ~5s after a deploy.
returns: 200 {"server":{...,"status":"ACTIVE","ipv4":"203.0.113.10"}}
POST /servers (auth)
Deploy one server. Async: 202 = accepted, not yet running.
body: {"label":"my-bot","planId":"vc2-1c-1gb","regionId":"ams"}
returns: 202 {"server":{...,"status":"PROVISIONING"}}
POST /servers/bulk (auth)
Deploy up to 10 servers in one call. Labels get -1..-N suffixes.
body: {"label":"fleet","count":10,"planId":"vc2-1c-1gb","regionId":"ams"}
returns: 202 {"servers":[...10 items, all "PROVISIONING"]}
DELETE /servers/:id (auth)
Destroy a server. Billing stops the same hour.
returns: 202 {"ok":true}
GET /backups (auth)
List your backups (full disk snapshots, kept 7 days).
returns: 200 {"backups":[{"id","label","status","region","plan","createdAt","expiresAt"}]}
POST /backups (auth)
Back up a server. Async: snapshot takes minutes, PENDING -> AVAILABLE.
body: {"serverId":"<id>"}
returns: 202 {"backup":{...,"status":"PENDING"}}
POST /backups/:id/restore (auth)
Restore an AVAILABLE backup onto a new server (gets a new IP).
returns: 202 {"server":{...,"status":"PROVISIONING"}}
DELETE /backups/:id (auth)
Delete a backup before its 7-day expiry.
returns: 202 {"ok":true}
## Catalog
plans: vc2-1c-1gb Micro (1 vCPU / 1 GB / 25 GB, $10/mo) · vc2-1c-2gb Starter (1 / 2 / 55, $18) · vc2-2c-4gb Standard (2 / 4 / 80, $34) · vc2-4c-8gb Pro (4 / 8 / 160, $62) · vc2-6c-16gb Beast (6 / 16 / 320, $120)
regions: ams fra par lon mad waw sto · ewr ord dfw atl mia sea lax sjc yto mex · sao scl · nrt icn sgp blr bom del · syd mel · jnb tlv
Hourly price is returned on the server object at deploy time and never changes
for a running server.
## Server statuses
PROVISIONING -> ACTIVE (success) | ERROR (failed, not billed further)
DESTROYING -> DESTROYED
SUSPENDED = balance ran out or abuse hold; server is off but recoverable.
## Backups
Full disk snapshots, kept 7 days, then auto-deleted.
POST /backups {"serverId"} -> snapshot (PENDING -> AVAILABLE, takes minutes).
POST /backups/<id>/restore -> new server from the snapshot (new IP, same plan/region).
Backup statuses: PENDING -> AVAILABLE | ERROR; EXPIRED once deleted.
## Errors
400 validation failed ("details" in body) | 401 token expired -> re-login, retry once
402 insufficient balance -> top up | 403 suspended or server limit (10 active)
404 not yours / not found | 409 already being destroyed
429 rate limited (100 req/min, 10/min on /auth/*) -> exponential backoff
## Rules for agents
- Deploys are asynchronous. 202 means accepted; poll GET /servers/:id every ~5 seconds until status is ACTIVE (typically ~60s) or ERROR.
- Access tokens expire after 15 minutes. On any 401, call POST /auth/login again and retry the request once.
- Money values (balance, hourlyPrice, hourlySpend) are strings — parse as decimal, never float-math them.
- Check GET /billing before deploying: the balance must cover at least one hour per server, or you get 402.
- Server labels must match ^[a-zA-Z0-9._-]+$ (max 64 chars).
- Account limit is 10 active servers. 403 with a limit message means destroy something first or ask for a raise via /docs/custom-requests.
- Rate limit is 100 requests/minute (10/min on auth routes). On 429, back off exponentially.
- Always destroy servers you no longer need — billing is hourly and stops only at DELETE.
- Backups are full disk snapshots kept 7 days. POST /backups is async (PENDING -> AVAILABLE, minutes); only restore once AVAILABLE. Restore creates a new server with a new IP.
Endpoint reference
JSON in, JSON out. Authorization: Bearer <accessToken> on everything marked auth.
/auth/registerCreate an account. Email + password is all that is needed.
body: {"email":"[email protected]","password":"min-8-chars"}
returns: 201 {"accessToken":"<jwt>","user":{"id","email","balance"}}
/auth/loginGet a fresh access token (expires in 15 minutes).
body: {"email":"...","password":"..."}
returns: 200 {"accessToken":"<jwt>","user":{...}}
/auth/meauthWhoami: id, email and current balance.
returns: 200 {"user":{"id","email","balance":"9.96"}}
/billingauthBalance and total hourly spend across active servers.
returns: 200 {"balance":"9.96","hourlySpend":"0.012"}
/serversauthList all non-destroyed servers.
returns: 200 {"servers":[{"id","label","status","region","plan","ipv4","hourlyPrice","createdAt"}]}
/servers/:idauthOne server. Poll this every ~5s after a deploy.
returns: 200 {"server":{...,"status":"ACTIVE","ipv4":"203.0.113.10"}}
/serversauthDeploy one server. Async: 202 = accepted, not yet running.
body: {"label":"my-bot","planId":"vc2-1c-1gb","regionId":"ams"}
returns: 202 {"server":{...,"status":"PROVISIONING"}}
/servers/bulkauthDeploy up to 10 servers in one call. Labels get -1..-N suffixes.
body: {"label":"fleet","count":10,"planId":"vc2-1c-1gb","regionId":"ams"}
returns: 202 {"servers":[...10 items, all "PROVISIONING"]}
/servers/:idauthDestroy a server. Billing stops the same hour.
returns: 202 {"ok":true}
/backupsauthList your backups (full disk snapshots, kept 7 days).
returns: 200 {"backups":[{"id","label","status","region","plan","createdAt","expiresAt"}]}
/backupsauthBack up a server. Async: snapshot takes minutes, PENDING -> AVAILABLE.
body: {"serverId":"<id>"}
returns: 202 {"backup":{...,"status":"PENDING"}}
/backups/:id/restoreauthRestore an AVAILABLE backup onto a new server (gets a new IP).
returns: 202 {"server":{...,"status":"PROVISIONING"}}
/backups/:idauthDelete a backup before its 7-day expiry.
returns: 202 {"ok":true}
Catalog IDs
Plans: vc2-1c-1gb Micro (1 vCPU / 1 GB / 25 GB, $10/mo) · vc2-1c-2gb Starter (1 / 2 / 55, $18) · vc2-2c-4gb Standard (2 / 4 / 80, $34) · vc2-4c-8gb Pro (4 / 8 / 160, $62) · vc2-6c-16gb Beast (6 / 16 / 320, $120)
Regions: ams fra par lon mad waw sto · ewr ord dfw atl mia sea lax sjc yto mex · sao scl · nrt icn sgp blr bom del · syd mel · jnb tlv
Rules your agent should follow
- ▸Deploys are asynchronous. 202 means accepted; poll GET /servers/:id every ~5 seconds until status is ACTIVE (typically ~60s) or ERROR.
- ▸Access tokens expire after 15 minutes. On any 401, call POST /auth/login again and retry the request once.
- ▸Money values (balance, hourlyPrice, hourlySpend) are strings — parse as decimal, never float-math them.
- ▸Check GET /billing before deploying: the balance must cover at least one hour per server, or you get 402.
- ▸Server labels must match ^[a-zA-Z0-9._-]+$ (max 64 chars).
- ▸Account limit is 10 active servers. 403 with a limit message means destroy something first or ask for a raise via /docs/custom-requests.
- ▸Rate limit is 100 requests/minute (10/min on auth routes). On 429, back off exponentially.
- ▸Always destroy servers you no longer need — billing is hourly and stops only at DELETE.
- ▸Backups are full disk snapshots kept 7 days. POST /backups is async (PENDING -> AVAILABLE, minutes); only restore once AVAILABLE. Restore creates a new server with a new IP.
Servers for humans work here too
The same API powers the dashboard. Try it by hand first — deploy, poke around, destroy. Cents per hour.