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.

agent@cryptovps — llms.txt
Raw
# 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.

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/meauth

Whoami: id, email and current balance.

returns: 200 {"user":{"id","email","balance":"9.96"}}

GET/billingauth

Balance and total hourly spend across active servers.

returns: 200 {"balance":"9.96","hourlySpend":"0.012"}

GET/serversauth

List all non-destroyed servers.

returns: 200 {"servers":[{"id","label","status","region","plan","ipv4","hourlyPrice","createdAt"}]}

GET/servers/:idauth

One server. Poll this every ~5s after a deploy.

returns: 200 {"server":{...,"status":"ACTIVE","ipv4":"203.0.113.10"}}

POST/serversauth

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/bulkauth

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/:idauth

Destroy a server. Billing stops the same hour.

returns: 202 {"ok":true}

GET/backupsauth

List your backups (full disk snapshots, kept 7 days).

returns: 200 {"backups":[{"id","label","status","region","plan","createdAt","expiresAt"}]}

POST/backupsauth

Back up a server. Async: snapshot takes minutes, PENDING -> AVAILABLE.

body: {"serverId":"<id>"}

returns: 202 {"backup":{...,"status":"PENDING"}}

POST/backups/:id/restoreauth

Restore an AVAILABLE backup onto a new server (gets a new IP).

returns: 202 {"server":{...,"status":"PROVISIONING"}}

DELETE/backups/:idauth

Delete 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.