Skip to main content
Every purchase through the API is paid from your account balance in the same request: either it is paid, or nothing happened. There are no coupons, no crypto payments and no partial payments through the API. Top up your balance first in the dashboard, see Top up account credit. All amounts are whole euro cents, VAT included where the field says so. Read your balance with GET /v1/balance (scope billing.read).

What your token needs

billing.manage spends the account owner’s balance, also when a team member’s token uses it. Only a member with two-factor authentication can create a token with it.

Prices come from us, expectedTotal protects you

You never send a price. The server computes it from the plan, the term and your confirmed tax country. What you can send is expectedTotal: the total you saw and agreed to. If the price at the moment of the purchase is anything else, the request fails with 409 EXPECTED_TOTAL_MISMATCH and nothing is charged. Quote again and decide. Where expectedTotal comes from: expectedTotal is optional. Without it, you pay the current price.

The idempotency key

Orders, renewals, upgrades and IP changes need an Idempotency-Key header with a UUID. Use one new key per purchase you mean to make, and the same key when you retry that purchase:
  • A retry with the same key and the same body returns the same result and charges once. For an upgrade or an IP change it also shows the current status.
  • The same key with another body, or for another server, is 409.
  • Keys belong to the account, not to the token: every token of the account shares them. Orders and renewals share one key space; upgrades and IP changes each have their own.
So if a request times out, send it again with the same key. You will never pay twice for it.

Order a server

1

Pick location, plan and image

GET /v1/locations lists the location codes. GET /v1/plans?location=DE lists the plans there with their billing cycles, list prices (netAmount, before VAT), whether they are available, and whether backups are purchasable, included or unavailable. GET /v1/images lists the image slugs.
2

Get a quote

POST /v1/quotes with planId, locationCode, billingCycle and optionally backups returns the exact first-term price under your tax profile: subtotal, taxRate, taxAmount, total, and renewalTotal. A quote reserves no stock and charges nothing.
3

Order

POST /v1/orders with the same fields plus osType (the image slug), and optionally name, sshKey (Linux images) and expectedTotal. It answers 201 with the order.
4

Follow the build

Poll GET /v1/orders/{id}. Once the server exists, serverId names it; follow it with GET /v1/servers/{id}. If you use webhooks, vm_ready tells you when it is built and running.
In a real script, generate the key once, store it with the purchase, and reuse it on every retry. A fresh uuidgen on each attempt would place a second order. Why an order can be refused, with nothing charged and no order left behind:

Order statuses

Poll while the order is pending_payment or provisioning, and for about 15 minutes after failed.

When a build fails

You never pay for a server that was not built. If a paid server order is still not built 24 hours after its payment, what you paid for it goes back to your account balance automatically and the order becomes refunded. You get an email, and an order_refunded webhook if you subscribed to it. Until then our team may still retry the build, and the order can still end as completed.

Renew a server

POST /v1/servers/{id}/renew with an Idempotency-Key and a billingCycle (1month, 3months, 6months or 12months) adds that term to the server and charges it to your balance. Optionally send expectedTotal. It answers 201 with a renewal order (kind: "renewal"). The order is provisioning until the new term is applied, then completed; follow it with GET /v1/orders/{id}. The server’s new end date is expiresAt in GET /v1/servers/{id}.
  • Open renewal invoice: we raise a renewal invoice 14 days before a server expires. While it is open, the renewal pays that invoice, on its own term. Another billingCycle is 409 RENEWAL_INVOICE_OPEN.
  • Which servers: running, stopped and suspended servers renew. A server being deleted, deleted or not built yet is 409 VM_STATE_INVALID.
  • One at a time: while another paid renewal of the server is still being applied, a new one is 409 CONFLICT.
  • Too little balance is 400 INSUFFICIENT_BALANCE and changes nothing.

Auto-renew

With autoRenew on, the server is renewed from your balance when its term ends, on its billing cycle. If your balance will not cover the renewal, we notify you 3 days before the server expires, so you can top up in time. autoRenew in GET /v1/servers/{id} shows the current setting.

Upgrade a server

1

List the options

GET /v1/servers/{id}/upgrade-options lists the larger plans sold where the server runs, each priced for the days left in its term (daysRemaining), VAT included. An empty list means none fits now.
2

Buy one

POST /v1/servers/{id}/upgrades with an Idempotency-Key, the option’s plan.id as planId and optionally its total as expectedTotal. It answers 201 with the upgrade.
3

Wait for it

The upgrade is paid, then processing, then completed. Poll GET /v1/servers/{id} for the new cores, memoryMb and diskGb, or repeat the request with the same key to see the upgrade’s status.
A running server is switched off and on again once for the upgrade, without a shutdown, and is offline for about 2 minutes. Save open work first. A stopped server stays stopped.
Only a running or stopped server whose term has not ended can be upgraded (400 VM_STATE_INVALID otherwise, also for a suspended one). While another upgrade is paid or being applied, it is 400 UPGRADE_IN_PROGRESS; without room on the server’s host, 400 UPGRADE_NO_CAPACITY. If an upgrade ends as failed before the server was touched, the charge goes back to your balance.

Change the IP address

GET /v1/servers/{id}/ip-change shows whether a new IPv4 address can be bought now (available), when the cooldown ends (cooldownUntil) and what it costs (total, VAT included). POST /v1/servers/{id}/ip-changes with an Idempotency-Key buys it. Send {} as the body, or {"expectedTotal": <total>}. It needs the scopes vms.manage and billing.manage. It answers 201 with the change, paid until it is applied right after; newIp holds the new address once one is reserved.
  • The old address stops working. A running Linux server restarts once to take the new address and is briefly unreachable. A running Windows server switches over live, which ends every connection to the old address. A stopped server takes it when it next starts.
  • Cooldown: one change per server every 7 days. A change inside it is 409 CONFLICT, naming when the cooldown ends.
  • Only a running or stopped server (409 VM_STATE_INVALID otherwise). While another change is paid or being applied, 409 IP_CHANGE_IN_PROGRESS. No free address on the host is 400.
  • A change that ends as failed is not refunded automatically: contact support.