Vitamin API reference
Sell and manage VPN accounts and virtual servers from your own site, bot or script.
Base URLhttps://apiservice.vitamindata.net/api/v1
Keys are issued in your panel. If you do not see the section, ask support to switch API access on for your account.
1Create an API key in your panel and send it as a bearer token on every call.
2Call Ping to prove the key, then pull your prices with ListPlans and GetVPSStorefront.
3Sell with FUNDING_AUTO: your balance pays when it covers, your customer gets a payment link when it does not.
Authentication
Every request carries your key as a bearer token. There are no cookies on this host and no CSRF token to fetch — a key is the whole credential.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Keys are created in your panel under API. The secret is shown once, at creation: we store only a hash of it, so if it is lost the fix is to rotate the key — which issues a new secret and keeps the old one working for a day, so you can deploy without downtime.
A key can be limited to a list of source addresses, given its own per-minute rate limit, and have individual operations withheld from it. Those are set by our operators — ask support if you need a key that, say, may buy but may never delete a service.
Test keys
A key beginning sk_test_ reads real data but refuses anything that would spend money or touch a real machine, so you can wire up and verify your integration before it can cost anything.
What a failure looks like
An unknown key and a key whose account has no API access answer the same 401, word for word: the answer never confirms whether a key exists. A key of yours that outlived its rotation overlap is the exception — it says api key expired, because you already know that key was real and you need to know why it stopped. Repeated failures from one address are throttled — see rate limits.
Paying for things
Everything you buy — a VPN account, an extension, a server, a renewal, an upgrade — goes through one contract. You choose how it is funded:
funding | What happens |
|---|
FUNDING_AUTO | Recommended. Takes it from your balance if the balance covers it; otherwise the call still succeeds and hands you a payment link. One call, no error to interpret. |
FUNDING_BALANCE | Balance only. If the balance is short the call FAILS with insufficient_balance (the error still carries a payable link). |
FUNDING_INVOICE | Always returns a payment link, even if your balance would have covered it. |
With FUNDING_AUTO you branch on one field:
{"order": {...}, "paid": true, "status": "completed"}
{"order": {...}, "status": "payment_required",
"invoice": {"invoice_id": "inv_9m2r4t",
"pay_url": "https://pay.example.com/i/inv_9m2r4t",
"price_usd": "11.90", "expires_at": "1785499200"}}
completed means the money is taken and delivery has started — poll GetOrder until its status is delivered. payment_required means send your customer to pay_url; delivery starts by itself when the invoice is paid.
Prices are always ours. You may send expected_total_usd as a guard: if our fresh quote differs, the sale is refused with price_changed and the new total, rather than charging a number your customer never saw.
Retrying safely
Send an Idempotency-Key header on every call that spends money. If a response never reaches you — a timeout, a dropped connection, a redeployed worker — retry the SAME request with the SAME key and you get the original outcome back instead of a second charge.
Idempotency-Key: 8f14e45f-ea6d-4b3a-9c1b-2f0d5a7e91c3
Use a fresh key per customer action (a UUID is ideal). Re-using a key with a different body is refused with idempotency_conflict — that combination means a bug, and guessing which request you meant would be worse than telling you.
Rate limits
Every authenticated response tells you where your key stands:
RateLimit-Limit: 6000
RateLimit-Remaining: 5987
RateLimit-Policy: 6000;w=60
The limit is per key, per minute, and it is set for your account — the default suits a storefront; a busy bot should ask for more rather than pace itself at the default. Exceeding it answers 429 with Retry-After.
A 429 also appears if a lot of requests from one address fail to authenticate. That is brute-force protection, not your quota: it clears by itself (the header says when), and a working key never triggers it.
You will also see an X-Ratelimit-* family on every response, including ones with no key. That is a coarse per-ADDRESS brake in front of the whole API, not your key's budget — pace against RateLimit-Remaining, and treat the X- headers as someone else's business.
Errors
Failures come back as an HTTP status and a JSON body. The top-level code is the transport category; the top-level message carries the stable machine code. The full detail — the same machine code, a safe sentence, and any actionable extras — rides in details under debug:
{"code": "failed_precondition",
"message": "insufficient_balance",
"details": [{"type": "neopay.seller.publicapi.v1.ErrorInfo",
"value": "CgptZXNzYWdl…",
"debug": {"code": "insufficient_balance",
"message": "insufficient balance",
"payUrl": "https://pay.example.com/i/inv_9m2r4t",
"orderId": "ord_8c3d1e",
"totalUsd": "11.90"}}]}
Two quirks of the error channel, both worth coding for: value is the base64 protobuf (ignore it — read debug), and inside debug the extra fields are lowerCamelCase — payUrl, orderId, totalUsd, retryAfterSeconds — a Connect convention, unlike the snake_case everywhere else. Branch on the top-level message or on debug.code; never on the sentence.
Refusals before your request is authorized
A request that never reaches a handler — no key or a bad one (401), a source address the key does not allow (403), a rate limit (429), an authentication outage (503) — is refused by the front door, and the front door answers a SHORTER body: a transport code and a plain sentence, with no details and no machine code.
{"code": "unauthenticated", "message": "invalid api key"}
So branch on the HTTP STATUS for these (and honour Retry-After on a 429); the machine codes below belong to calls that got as far as a handler. The coarse per-address brake is older still and answers {"error":"rate_limited"} — keyed error, not code.
| Code | Means | What to do |
|---|
forbidden_scope | The key lacks the scope for this call, or this operation has been withheld from it. | Ask support to widen the key. |
not_found | No such object for this account. | Check the id. A foreign id also answers this — by design. |
invalid_request | A field is malformed. | Fix and resend; retrying unchanged will not help. |
insufficient_balance | Balance-only funding could not cover it. | Use the payUrl in the detail, or switch to FUNDING_AUTO. |
price_changed | Your expected_total_usd no longer matches. | Re-quote and confirm the new total with your customer. |
idempotency_conflict | That key was used with a different body. | Use a fresh key per action. |
sandbox_unavailable | A sk_test_ key tried to spend money or touch a real machine. | Expected — use a live key for that call. Test keys read, they never buy. |
unpriceable | The configuration you asked for is not sellable — an unpriced plan or node, or a cart that no model covers. | Re-read the storefront and quote before you buy; a quote refuses the same cart. |
upstream_unavailable | A plane we depend on is down. | Retry with backoff; reads may be briefly stale. |
order_failed | Delivery failed after payment. | Do not re-buy. Poll GetOrder; we recover these automatically and support can see it. |
internal | Something broke on our side that we did not classify. | Retry once with backoff; if it repeats, quote the X-Request-Id to support. |
Conventions
- Transport. Every call is
POST {base}/{Method} with a JSON body — POST /api/v1/CreateVPNOrder. Nothing else exists: any other HTTP method answers 405, there is no REST verb mapping and there are no path parameters. - Money is a string.
"19.99", never 19.99: a JSON number is a float in most languages and cannot hold a cent exactly. - 64-bit integers arrive as strings. Every byte count and every unix timestamp is 64-bit, and the wire quotes them —
"remaining_bytes": "96636764160". Parse them as integers; on requests you may send either form. - Zero is omitted. A field whose value is
0, false or empty does not appear in a response at all. Treat absent as zero — and remember a 0 daily limit means NO limit, not "0 GB". - Times are unix seconds, except the transaction window, which takes and returns RFC3339 or
YYYY-MM-DD. - Traffic is bytes, never gigabytes, on every figure.
- Ids are opaque.
acc_…, ord_…, vpn_…. Never parse or generate one, and never assume they are sequential. - Paging is by opaque cursor: pass the previous response's
next_cursor back. An empty next_cursor means you have everything. - The field tables use short type tokens.
money — an exact decimal string; unix — unix seconds (64-bit, so a string); bytes — a byte count (64-bit, so a string); int64 — any other 64-bit (a string); int — 32-bit, a plain number; cursor — an opaque paging handle; enum — exactly one of the listed values. - New fields appear without warning and existing ones do not change meaning. Ignore what you do not recognise.
Getting started
The one call to make first: it proves the key works and tells you which account it belongs to.
https://apiservice.vitamindata.net/api/v1/PingAnswers your account id, whether the key is live or test, and our clock.
Request
No parameters — send an empty object, {}.
Example requestcurl https://apiservice.vitamindata.net/api/v1/Ping \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}'
Response200 · application/json
account_idstring
The key's account — proof the key resolved.
modeenum
Which kind of key you sent.
One of:livetest
server_timeunix
Our clock — useful for spotting drift before it breaks signatures or windows.
Sample response{
"account_id": "acc_9f3k2m7q",
"mode": "live",
"server_time": "1785412800"
}
Account and balance
https://apiservice.vitamindata.net/api/v1/GetAccountYour account's email, status, locale and whether the address is verified.
Request
No parameters — send an empty object, {}.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetAccount \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}'
Response200 · application/json
accountobject
Your account.
account.account_idstring
Public id (acc_…).
account.emailstring
The login address.
account.statusstring
active unless the account is restricted.
account.localestring
The account's language — card names and notifications localize to it.
account.email_verifiedbool
The address has been confirmed.
account.created_atunix
When the account was created.
Sample response{
"account": {
"account_id": "acc_9f3k2m7q",
"email": "dev@example.com",
"status": "active",
"locale": "en",
"email_verified": true,
"created_at": "1769000000"
}
}
https://apiservice.vitamindata.net/api/v1/GetBalanceYour ledger balance and what a purchase can actually draw on.
available_usd is the number to check before buying — it excludes anything already locked by an in-flight order.
Request
No parameters — send an empty object, {}.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetBalance \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}'
Response200 · application/json
balance_usdmoney
The full ledger balance.
available_usdmoney
Balance minus locks — what a purchase can spend right now.
as_ofstring
The ledger timestamp of the figures, RFC3339.
Sample response{
"balance_usd": "72.60",
"available_usd": "60.70",
"as_of": "2026-07-29T12:00:00Z"
}
https://apiservice.vitamindata.net/api/v1/ListTransactionsYour ledger, newest first.
Defaults to the last three months. A window wider than 92 days is narrowed, and the response tells you the window it actually used — so a short answer is never ambiguous.
Request
limitintoptional
Page size. Default 25, max 100.
cursorcursoroptional
The previous response's next_cursor. Omit it for the first page.
kindstringoptional
Optional comma-separated filter over the kind values below.
fromstringoptional
Window start, RFC3339 or YYYY-MM-DD.
tostringoptional
Window end. A date-only to includes that whole day.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ListTransactions \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"limit":25,"cursor":"","kind":"topup_credit,invoice_debit_reserved","from":"2026-05-01","to":"2026-07-30"}'
Response200 · application/json
transactionsarray
The ledger rows.
transactions[].idstring
The ledger row's id.
transactions[].tsstring
When, RFC3339.
transactions[].kindenum
What moved the money. topup_credit is a paid top-up; the two invoice_debit_* kinds are purchases. An in-flight order's internal hold and release are not part of this feed.
One of:topup_creditexternal_creditinvoice_debit_reservedinvoice_debit_externaloverpay_creditmanual_creditmanual_debitspend_debitspend_refundautomated_correction
transactions[].amount_usdmoney
Signed — negative on debits.
transactions[].balance_after_usdmoney
The running balance after this row.
transactions[].ref_invoice_idstring
The invoice behind the movement — feed it to GetInvoice for the full story.
transactions[].descriptionstring
A short human label. Display-only; never branch on it.
next_cursorcursor
Pass it back as cursor for the next page. Absent/empty = you have everything.
has_morebool
More rows exist beyond this page.
fromstring
The window ACTUALLY applied (RFC3339). Narrower than you asked ⇒ you hit the 92-day cap.
tostring
The applied window's end.
Sample response{
"transactions": [
{"id": "tx_01j9zq", "ts": "2026-07-28T09:14:03Z", "kind": "invoice_debit_reserved",
"amount_usd": "-11.90", "balance_after_usd": "72.60",
"ref_invoice_id": "inv_5k8p2q", "description": "order ord_7b2c9d"},
{"id": "tx_01j8xw", "ts": "2026-07-25T18:40:11Z", "kind": "topup_credit",
"amount_usd": "50.00", "balance_after_usd": "84.50", "ref_invoice_id": "inv_3d1x8n"}
],
"from": "2026-04-30T00:00:00Z",
"to": "2026-07-29T23:59:59Z"
}
POST
CreateTopup
buyIdempotency-Key
https://apiservice.vitamindata.net/api/v1/CreateTopupCreates a payable invoice that adds funds to your balance.
Send your customer (or yourself) to invoice.pay_url. The balance moves when it is paid.
Request
amount_usdmoneyrequired
How much to add, as a decimal string.
Example requestcurl https://apiservice.vitamindata.net/api/v1/CreateTopup \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"amount_usd":"50.00"}'
Response200 · application/json
invoiceobject
The payable invoice.
invoice.invoice_idstring
The gateway's invoice id (inv_…).
invoice.statusenum
pending is payable. Everything from confirmed through delivered_redirected means the money is irreversibly in — treat all of those as PAID. expired means the link lapsed unpaid.
One of:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring
The hosted payment page. Send your customer here; every rail (coins, chains, balance) lives behind it.
invoice.pay_telegram_urlstring
The same invoice, payable inside Telegram: it opens the payment provider's own bot, which shows the amount and takes the payment there. Offer it beside pay_url for customers who would rather not leave the app. May be absent — only a payment provider with a bot configured has one, so never make it your only pay button.
invoice.price_usdmoney
What the invoice collects.
invoice.expires_atunix
When the payment window closes.
Sample response{
"invoice": {
"invoice_id": "inv_3d1x8n",
"status": "pending",
"pay_url": "https://pay.example.com/i/inv_3d1x8n",
"pay_telegram_url": "https://t.me/VitaminPayBot?start=3d1x8n",
"price_usd": "50.00",
"expires_at": "1785499200"
}
}
https://apiservice.vitamindata.net/api/v1/GetInvoiceOne payment in full detail, including what the chain shows.
A ledger row's ref_invoice_id is the join key. Only invoices your own account created can be read.
Request
invoice_idstringrequired
From a ledger row's ref_invoice_id, an order, or a top-up.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetInvoice \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"invoice_id":"inv_5k8p2q"}'
Response200 · application/json
invoiceobject
The invoice itself.
invoice.invoice_idstring
The gateway's invoice id (inv_…).
invoice.statusenum
pending is payable. Everything from confirmed through delivered_redirected means the money is irreversibly in — treat all of those as PAID. expired means the link lapsed unpaid.
One of:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring
The hosted payment page. Send your customer here; every rail (coins, chains, balance) lives behind it.
invoice.pay_telegram_urlstring
The same invoice, payable inside Telegram: it opens the payment provider's own bot, which shows the amount and takes the payment there. Offer it beside pay_url for customers who would rather not leave the app. May be absent — only a payment provider with a bot configured has one, so never make it your only pay button.
invoice.price_usdmoney
What the invoice collects.
invoice.expires_atunix
When the payment window closes.
paymentsarray
What the chain shows. Empty for a balance-funded invoice (no chain was involved) and for one nobody has paid yet — an empty list is not an error.
payments[].chainstring
The network the payment arrived on (tron, bsc, …).
payments[].assetstring
What was paid (USDT, …).
payments[].amountmoney
The asset amount, exact.
payments[].tx_hashstring
The on-chain transaction — your customer's proof of payment.
payments[].confirmedbool
The chain has finalised it.
payments[].seen_atunix
When we first observed it.
order_idstring
What the invoice bought. Absent for a top-up, which buys nothing.
Sample response{
"invoice": {
"invoice_id": "inv_5k8p2q",
"status": "confirmed",
"pay_url": "https://pay.example.com/i/inv_5k8p2q",
"price_usd": "11.90",
"expires_at": "1785499200"
},
"payments": [
{"chain": "tron", "asset": "USDT", "amount": "11.90",
"tx_hash": "c4a1f09e2b7d", "confirmed": true, "seen_at": "1785412920"}
],
"order_id": "ord_7b2c9d"
}
Prices
Nothing here creates anything — quote as often as you like before your customer commits.
https://apiservice.vitamindata.net/api/v1/ListPlansWhat you may sell: the slider's bounds and, if your storefront uses them, the fixed-price cards.
Render whichever is populated. A card is bought by putting its bundle_id in the cart; a slider cart uses gb/months/users.
Request
No parameters — send an empty object, {}.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ListPlans \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}'
Response200 · application/json
model_namestring
Your storefront's pricing model.
model_typestring
Its engine version.
boundsobject
The configurator's rules — every quote and order re-checks them server-side.
bounds.gb_minint
Smallest traffic a cart may ask for.
bounds.gb_stepint
The slider's step.
bounds.users_minint
Fewest concurrent devices.
bounds.months_minint
Shortest term.
bounds.months_maxint
Longest.
bounds.new_accounts_maxint
Most accounts one order may mint.
bounds.extend_maxint
Most accounts one order may extend.
bounds.default_gbint
A sensible slider default.
bounds.default_usersint
Default devices.
bounds.default_monthsint
Default term.
bundlesarray
The fixed-price cards, when your storefront is a card catalogue.
bundles[].bundle_idstring
The handle to put in cart.bundle_id.
bundles[].namestring
The card's name, already localized for the account's locale.
bundles[].gbint
Traffic included.
bundles[].monthsint
Validity.
bundles[].online_usersint
Concurrent devices.
bundles[].price_usdmoney
The price. It IS the price — no quote needed for a card.
bundles[].highlightbool
The storefront's featured card.
bundles[].daily_cap_gbint
Daily cap in GB. Absent = none.
Sample response{
"model_name": "vpn_dynamic",
"model_type": "dynamic_v2",
"bounds": {
"gb_min": 10, "gb_max": 500, "gb_step": 10,
"users_min": 1, "users_max": 10,
"months_min": 1, "months_max": 12,
"new_accounts_max": 5, "extend_max": 10,
"default_gb": 100, "default_users": 3, "default_months": 1
},
"bundles": [
{"bundle_id": "card_100_1m", "name": "100 GB · 1 month", "gb": 100, "months": 1,
"online_users": 3, "price_usd": "11.90", "highlight": true}
]
}
https://apiservice.vitamindata.net/api/v1/QuoteThe final price of a VPN cart, itemised. Discounts are already applied.
Request
cartobjectrequired
The cart to price.
cart.kindenumrequired
Buy new accounts, or add traffic and time to existing ones.
One of:newextend
cart.gbintoptional
Traffic per account, in GB, within the bounds from ListPlans.
cart.monthsintoptional
Validity per account, in months.
cart.usersintoptional
Concurrent devices per account.
cart.new_accountsintoptional
kind:"new" only: how many accounts to mint. Usernames are server-minted.
cart.extend_vpn_idsarrayoptional
kind:"extend" only: the accounts to extend, by public id.
cart.bundle_idstringoptional
Buys a fixed-price card from ListPlans.bundles instead of a configured cart. When set, gb/months/users are ignored — the card's own values and price apply.
Example requestcurl https://apiservice.vitamindata.net/api/v1/Quote \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"cart":{"kind":"new","gb":100,"months":1,"users":3,"new_accounts":2}}'
Other shapes of this requestExtend accounts you already hold{"cart":{"kind":"extend","gb":50,"months":1,"users":3,"extend_vpn_ids":["vpn_6t2k9p","vpn_1a4b7c"]}}
Buy a fixed-price card instead of a configured cart{"cart":{"kind":"new","bundle_id":"card_100_1m","new_accounts":1}}
Response200 · application/json
quoteobject
The itemised price. Nothing is created and nothing is charged.
quote.model_namestring
Which pricing model answered.
quote.model_typestring
The model's engine version.
quote.base_usdmoney
The price before discounts and surcharges.
quote.total_usdmoney
The final price — what a sale with this cart charges.
quote.linesarray
The itemisation, signed, summing exactly to the total.
quote.lines[].codestring
What this row is (base, a discount code, a surcharge…).
quote.lines[].kindstring
The row's category, for grouping in your UI.
quote.lines[].amount_usdmoney
Signed. Discounts are negative; the rows sum exactly to total_usd.
quote.lines[].pctstring
The percentage behind the row, when there is one.
quote.cappedbool
The total hit the model's ceiling.
quote.floor_appliedbool
The total was raised to the model's floor.
quote.clampedenum
Set when a cart value was clamped into bounds before pricing.
One of:minmax
quote.invalidstring
Non-empty means the cart cannot be priced — show it and NEVER charge such a quote.
quote.metamap
Model extras, string→string (e.g. an upgrade's remaining_days).
Sample response{
"quote": {
"model_name": "vpn_dynamic",
"model_type": "dynamic_v2",
"base_usd": "14.00",
"total_usd": "11.90",
"lines": [
{"code": "base", "kind": "base", "amount_usd": "14.00"},
{"code": "loyalty", "kind": "discount", "amount_usd": "-2.10", "pct": "15"}
]
}
}
Selling VPN
POST
CreateVPNOrder
buyIdempotency-Key
https://apiservice.vitamindata.net/api/v1/CreateVPNOrderBuys new VPN accounts, or extends existing ones ("kind":"extend" with extend_vpn_ids).
See Paying for things for the two shapes the response can take.
Request
cartobjectrequired
What to buy — the same shape Quote prices.
cart.kindenumrequired
Buy new accounts, or add traffic and time to existing ones.
One of:newextend
cart.gbintoptional
Traffic per account, in GB, within the bounds from ListPlans.
cart.monthsintoptional
Validity per account, in months.
cart.usersintoptional
Concurrent devices per account.
cart.new_accountsintoptional
kind:"new" only: how many accounts to mint. Usernames are server-minted.
cart.extend_vpn_idsarrayoptional
kind:"extend" only: the accounts to extend, by public id.
cart.bundle_idstringoptional
Buys a fixed-price card from ListPlans.bundles instead of a configured cart. When set, gb/months/users are ignored — the card's own values and price apply.
fundingenumrequired
How to pay — see Paying for things. There is no default: omitting it is refused.
One of:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyoptional
Confirmation guard. If set and our fresh quote differs, the sale is refused with price_changed instead of charging a number your customer never saw.
Example requestcurl https://apiservice.vitamindata.net/api/v1/CreateVPNOrder \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"cart":{"kind":"new","gb":100,"months":1,"users":3,"new_accounts":1},"funding":"FUNDING_AUTO","expected_total_usd":"11.90"}'
Other shapes of this requestExtend accounts you already hold{"cart":{"kind":"extend","gb":50,"months":1,"users":3,"extend_vpn_ids":["vpn_6t2k9p"]},"funding":"FUNDING_AUTO"}
Buy a fixed-price card, paid from balance{"cart":{"kind":"new","bundle_id":"card_100_1m","new_accounts":1},"funding":"FUNDING_BALANCE"}
Response200 · application/json
orderobject
The order — poll GetOrder until its status is delivered.
order.order_idstring
The order's public id (ord_…).
order.productenum
What was bought.
One of:vpnvps
order.kindstring
The purchase shape: new, extend, upgrade…
order.statusenum
The lifecycle. delivered is the goal; needs_operator means the money is in and a human is finishing delivery — do not re-buy; expired means the invoice lapsed unpaid.
One of:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum
Which rail actually funded it. FUNDING_AUTO resolves to one of these.
One of:invoicebalance
order.total_usdmoney
What the order charges.
order.invoice_idstring
The invoice behind it — every order has one, whichever rail funded it.
order.itemsint
How many entitlements the order mints or extends.
order.created_atunix
When it was placed.
order.delivered_atunix
When delivery finished. Absent until then.
order.breakdownobject
The quote the customer agreed to, verbatim — the same shape Quote returns.
invoiceobject
The invoice behind the order: payable when payment_required, already settled when completed.
invoice.invoice_idstring
The gateway's invoice id (inv_…).
invoice.statusenum
pending is payable. Everything from confirmed through delivered_redirected means the money is irreversibly in — treat all of those as PAID. expired means the link lapsed unpaid.
One of:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring
The hosted payment page. Send your customer here; every rail (coins, chains, balance) lives behind it.
invoice.pay_telegram_urlstring
The same invoice, payable inside Telegram: it opens the payment provider's own bot, which shows the amount and takes the payment there. Offer it beside pay_url for customers who would rather not leave the app. May be absent — only a payment provider with a bot configured has one, so never make it your only pay button.
invoice.price_usdmoney
What the invoice collects.
invoice.expires_atunix
When the payment window closes.
paidbool
The money is captured. Absent (= false) with payment_required.
statusenum
THE field to branch on — see Paying for things.
One of:completedpayment_required
Sample response{
"order": {
"order_id": "ord_8c3d1e", "product": "vpn", "kind": "new",
"status": "invoiced", "funding": "invoice", "total_usd": "11.90",
"invoice_id": "inv_9m2r4t", "items": 1, "created_at": "1785412800"
},
"invoice": {
"invoice_id": "inv_9m2r4t", "status": "pending",
"pay_url": "https://pay.example.com/i/inv_9m2r4t",
"pay_telegram_url": "https://t.me/VitaminPayBot?start=9m2r4t",
"price_usd": "11.90", "expires_at": "1785499200"
},
"status": "payment_required"
}
https://apiservice.vitamindata.net/api/v1/GetOrderPoll this after buying: created → invoiced → paid → delivering → delivered.
Request
order_idstringrequired
From the order you placed.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetOrder \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"order_id":"ord_7b2c9d"}'
Response200 · application/json
orderobject
The order, with its full breakdown.
order.order_idstring
The order's public id (ord_…).
order.productenum
What was bought.
One of:vpnvps
order.kindstring
The purchase shape: new, extend, upgrade…
order.statusenum
The lifecycle. delivered is the goal; needs_operator means the money is in and a human is finishing delivery — do not re-buy; expired means the invoice lapsed unpaid.
One of:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum
Which rail actually funded it. FUNDING_AUTO resolves to one of these.
One of:invoicebalance
order.total_usdmoney
What the order charges.
order.invoice_idstring
The invoice behind it — every order has one, whichever rail funded it.
order.itemsint
How many entitlements the order mints or extends.
order.created_atunix
When it was placed.
order.delivered_atunix
When delivery finished. Absent until then.
order.breakdownobject
The quote the customer agreed to, verbatim — the same shape Quote returns.
invoiceobject
Populated only while the order still awaits payment — the same shape as everywhere else.
Sample response{
"order": {
"order_id": "ord_7b2c9d", "product": "vpn", "kind": "new",
"status": "delivered", "funding": "balance", "total_usd": "11.90",
"invoice_id": "inv_5k8p2q", "items": 1,
"created_at": "1785230043", "delivered_at": "1785230103",
"breakdown": {
"model_name": "vpn_dynamic",
"model_type": "dynamic_v2",
"base_usd": "14.00",
"total_usd": "11.90",
"lines": [
{"code": "base", "kind": "base", "amount_usd": "14.00"},
{"code": "loyalty", "kind": "discount", "amount_usd": "-2.10", "pct": "15"}
]
}
}
}
https://apiservice.vitamindata.net/api/v1/ListOrdersYour order history, newest first.
Request
limitintoptional
Page size. Default 25, max 100.
cursorcursoroptional
The previous response's next_cursor. Omit it for the first page.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ListOrders \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"limit":25,"cursor":""}'
Response200 · application/json
orders[].order_idstring
The order's public id (ord_…).
orders[].productenum
What was bought.
One of:vpnvps
orders[].kindstring
The purchase shape: new, extend, upgrade…
orders[].statusenum
The lifecycle. delivered is the goal; needs_operator means the money is in and a human is finishing delivery — do not re-buy; expired means the invoice lapsed unpaid.
One of:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
orders[].fundingenum
Which rail actually funded it. FUNDING_AUTO resolves to one of these.
One of:invoicebalance
orders[].total_usdmoney
What the order charges.
orders[].invoice_idstring
The invoice behind it — every order has one, whichever rail funded it.
orders[].itemsint
How many entitlements the order mints or extends.
orders[].created_atunix
When it was placed.
orders[].delivered_atunix
When delivery finished. Absent until then.
orders[].breakdownobject
The quote the customer agreed to, verbatim — the same shape Quote returns.
next_cursorcursor
Pass it back as cursor for the next page. Absent/empty = you have everything.
Sample response{
"orders": [
{"order_id": "ord_7b2c9d", "product": "vpn", "kind": "new", "status": "delivered",
"funding": "balance", "total_usd": "11.90", "invoice_id": "inv_5k8p2q",
"items": 1, "created_at": "1785230043", "delivered_at": "1785230103"}
]
}
Managing VPN
https://apiservice.vitamindata.net/api/v1/ListVPNEvery VPN account you hold, with traffic left and expiry.
Request
limitintoptional
Page size. Default 50, max 200.
cursorcursoroptional
The previous response's next_cursor. Omit it for the first page.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ListVPN \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"limit":25,"cursor":""}'
Response200 · application/json
vpns[].vpn_idstring
The public id every other VPN verb takes.
vpns[].usernamestring
The credential name shown in apps.
vpns[].statusstring
The account's state as the panel shows it — active unless suspended or expired.
vpns[].remaining_bytesbytes
Traffic left across all its bundles.
vpns[].total_downloadbytes
Lifetime download, as reported live by the VPN plane. In ListVPN this is always 0 — the list is served from the cached read model, which has no per-direction figures. Use used_bytes for a list, or GetVPN/GetVPNUsage for the split.
vpns[].total_uploadbytes
Lifetime upload. Same caveat as total_download: 0 in ListVPN.
vpns[].used_bytesbytes
Lifetime traffic actually spent (download + upload). This is the figure the estate maintains for every VPN, so it is correct on every endpoint including ListVPN.
vpns[].expires_atunix
When the account lapses.
vpns[].max_onlineint
Concurrent devices allowed.
vpns[].daily_limit_bytesbytes
Today's cap. Absent/0 = NO daily cap.
vpns[].daily_used_bytesbytes
Spent against today's cap.
vpns[].daily_reset_unixunix
When the daily counter resets.
vpns[].allowed_protocolsint
A protocol bitmask used by our apps. Treat it as opaque.
vpns[].cache_atunix
How fresh the figures are: they are as old as this timestamp unless live is set.
vpns[].created_atunix
When the account was minted.
vpns[].livebool
The figures came from the network just now rather than the cache.
next_cursorcursor
Pass it back as cursor for the next page. Absent/empty = you have everything.
Sample response{
"vpns": [{
"vpn_id": "vpn_6t2k9p",
"username": "u482913",
"status": "active",
"remaining_bytes": "96636764160",
"total_download": "10737418240",
"used_bytes": "11811160064",
"total_upload": "1073741824",
"expires_at": "1793188800",
"max_online": 3,
"cache_at": "1785412700",
"created_at": "1785000000"
}],
"next_cursor": "vpn_6t2k9p"
}
https://apiservice.vitamindata.net/api/v1/GetVPNOne account in detail. live:true means the figures came from the network just now.
Request
vpn_idstringrequired
The account's public id (vpn_…), from ListVPN or an order's delivery.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetVPN \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vpn_id":"vpn_6t2k9p"}'
Response200 · application/json
vpn.vpn_idstring
The public id every other VPN verb takes.
vpn.usernamestring
The credential name shown in apps.
vpn.statusstring
The account's state as the panel shows it — active unless suspended or expired.
vpn.remaining_bytesbytes
Traffic left across all its bundles.
vpn.total_downloadbytes
Lifetime download, as reported live by the VPN plane. In ListVPN this is always 0 — the list is served from the cached read model, which has no per-direction figures. Use used_bytes for a list, or GetVPN/GetVPNUsage for the split.
vpn.total_uploadbytes
Lifetime upload. Same caveat as total_download: 0 in ListVPN.
vpn.used_bytesbytes
Lifetime traffic actually spent (download + upload). This is the figure the estate maintains for every VPN, so it is correct on every endpoint including ListVPN.
vpn.expires_atunix
When the account lapses.
vpn.max_onlineint
Concurrent devices allowed.
vpn.daily_limit_bytesbytes
Today's cap. Absent/0 = NO daily cap.
vpn.daily_used_bytesbytes
Spent against today's cap.
vpn.daily_reset_unixunix
When the daily counter resets.
vpn.allowed_protocolsint
A protocol bitmask used by our apps. Treat it as opaque.
vpn.cache_atunix
How fresh the figures are: they are as old as this timestamp unless live is set.
vpn.created_atunix
When the account was minted.
vpn.livebool
The figures came from the network just now rather than the cache.
livebool
Fresh from the network. Absent = served from the read model, as old as cache_at.
Sample response{
"vpn": {
"vpn_id": "vpn_6t2k9p",
"username": "u482913",
"status": "active",
"remaining_bytes": "96636764160",
"total_download": "10737418240",
"used_bytes": "11811160064",
"total_upload": "1073741824",
"expires_at": "1793188800",
"max_online": 3,
"cache_at": "1785412700",
"created_at": "1785000000"
},
"live": true
}
https://apiservice.vitamindata.net/api/v1/GetVPNUsageTraffic used and left, plus today's cap if one applies.
Request
vpn_idstringrequired
The account's public id (vpn_…), from ListVPN or an order's delivery.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetVPNUsage \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vpn_id":"vpn_6t2k9p"}'
Response200 · application/json
remaining_bytesbytes
Traffic left.
total_downloadbytes
Lifetime download.
total_uploadbytes
Lifetime upload.
expires_atunix
When the account lapses.
daily_limit_bytesbytes
Today's cap. Absent = none.
daily_used_bytesbytes
Spent against today's cap.
daily_reset_unixunix
When the daily counter resets.
cache_atunix
Freshness of the figures when not live.
livebool
Fresh from the network just now.
seriesarray
Reserved for the historical usage series — empty today.
series[].tunix
Bucket start.
series[].rxbytes
Downloaded in the bucket.
series[].txbytes
Uploaded in the bucket.
Sample response{
"vpn_id": "vpn_6t2k9p",
"remaining_bytes": "96636764160",
"total_download": "10737418240",
"total_upload": "1073741824",
"expires_at": "1793188800",
"daily_limit_bytes": "53687091200",
"daily_used_bytes": "1273741824",
"daily_reset_unix": "1785456000",
"cache_at": "1785412700",
"live": true
}
https://apiservice.vitamindata.net/api/v1/ListVPNBundlesThe traffic wallets behind one account, in the order they will be consumed.
This is how you answer "why did my customer's paid traffic go down while they had free traffic left?" — queue_position 1 is what drains next. live:false means we could not read them, which is not the same as having none.
Request
vpn_idstringrequired
The account's public id (vpn_…), from ListVPN or an order's delivery.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ListVPNBundles \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vpn_id":"vpn_6t2k9p"}'
Response200 · application/json
bundlesarray
The wallets, in consumption order.
bundles[].bundle_idstring
The wallet's id.
bundles[].freebool
Granted by the free tier rather than bought.
bundles[].sourceenum
Where the wallet came from.
One of:buyextendmigratedfree_tier
bundles[].granted_bytesbytes
Its full size when granted.
bundles[].remaining_bytesbytes
What is left in it.
bundles[].granted_atunix
When it was granted.
bundles[].expires_atunix
When it lapses whether or not it is spent.
bundles[].daily_limit_bytesbytes
Its own daily cap. Absent = none.
bundles[].statusenum
Spelled, not numbered, so you never have to learn that 2 means exhausted.
One of:activedisabledexhausted
bundles[].queue_positionint
1-based over the USABLE wallets, in consumption order — 1 drains next. 0/absent means it is out of the queue (spent, expired or disabled).
bundles[].plan_gbint
The size it was sold as, in GB.
bundles[].plan_daysint
The validity it was sold as, in days.
bundles[].invoice_idstring
The purchase it came from. Absent on a free grant.
livebool
Absent/false = the entitlement plane was unreachable, so the list is EMPTY rather than wrong. "We could not read them" and "there are none" are different sentences.
Sample response{
"bundles": [
{"bundle_id": "bnd_2m8x", "source": "buy",
"granted_bytes": "107374182400", "remaining_bytes": "96636764160",
"granted_at": "1785000000", "expires_at": "1793188800",
"status": "active", "queue_position": 1, "plan_gb": 100, "plan_days": 30,
"invoice_id": "inv_5k8p2q"},
{"bundle_id": "bnd_9k1f", "free": true, "source": "free_tier",
"granted_bytes": "5368709120", "remaining_bytes": "5368709120",
"granted_at": "1784000000", "expires_at": "1793188800",
"status": "active", "queue_position": 2, "plan_gb": 5, "plan_days": 30}
],
"live": true
}
POST
GetSubscriptionLink
read
https://apiservice.vitamindata.net/api/v1/GetSubscriptionLinkThe subscription URL a customer's app imports. This is the deliverable of a VPN sale.
Request
vpn_idstringrequired
The account's public id (vpn_…), from ListVPN or an order's delivery.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetSubscriptionLink \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vpn_id":"vpn_6t2k9p"}'
Response200 · application/json
subscription_urlstring
Hand this to your customer's app — it is the whole delivery.
tokenstring
The bare token, for building your own QR or app-import links.
Sample response{
"subscription_url": "https://sub.example.com/s/9f3kq8x2",
"token": "9f3kq8x2"
}
POST
SetVPNPassword
credentials
https://apiservice.vitamindata.net/api/v1/SetVPNPasswordChanges an account's password.
Needs the separate credentials scope — it is never implied by manage.
Request
vpn_idstringrequired
The account's public id (vpn_…), from ListVPN or an order's delivery.
new_passwordstringrequired
The password to set.
credentialstringoptional
Which credential, for multi-credential accounts. Empty = the primary one.
Example requestcurl https://apiservice.vitamindata.net/api/v1/SetVPNPassword \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vpn_id":"vpn_6t2k9p","new_password":"s3cr3t-Enough","credential":""}'
Response200 · application/json
usernamestring
The credential the change landed on.
Sample response{"username": "u482913"}
https://apiservice.vitamindata.net/api/v1/SetVPNStateSuspends or resumes an account.
Request
vpn_idstringrequired
The account's public id (vpn_…), from ListVPN or an order's delivery.
stateenumrequired
What to do.
One of:suspendresume
Example requestcurl https://apiservice.vitamindata.net/api/v1/SetVPNState \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vpn_id":"vpn_6t2k9p","state":"suspend"}'
Response200 · application/json
statusenum
The state the account settled in.
One of:suspendedactive
Sample response{"status": "suspended"}
https://apiservice.vitamindata.net/api/v1/DeleteVPNDeletes an account. There is no undo and no refund.
Request
vpn_idstringrequired
The account's public id (vpn_…), from ListVPN or an order's delivery.
Example requestcurl https://apiservice.vitamindata.net/api/v1/DeleteVPN \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vpn_id":"vpn_6t2k9p"}'
Response200 · application/json
statusenum
Always deleted on success.
One of:deleted
Sample response{"status": "deleted"}
Selling servers
A VPS sale is the same funding contract as a VPN sale — only the cart differs.
https://apiservice.vitamindata.net/api/v1/GetVPSStorefrontLocations, the plans priced at each, and the bootable images.
A node with available:false is out of capacity — show it, do not offer it.
Request
No parameters — send an empty object, {}.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetVPSStorefront \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}'
Response200 · application/json
nodesarray
The locations, each with its own priced plans.
nodes[].node_idstring
What a cart's node_id takes.
nodes[].labelstring
Display name (Frankfurt).
nodes[].regionstring
Coarse region code for grouping.
nodes[].countrystring
ISO country code, for flags.
nodes[].availablebool
Absent/false = out of capacity: show it, do not offer it.
nodes[].plansarray
What is sellable here, priced.
nodes[].plans[].plan_codestring
What a cart's plan_code takes.
nodes[].plans[].namestring
Display name.
nodes[].plans[].vcpuint
Cores.
nodes[].plans[].ram_mbint
Memory in MB.
nodes[].plans[].disk_gbint
Disk in GB.
nodes[].plans[].traffic_bytesbytes
Monthly traffic included.
nodes[].plans[].price_usd_monthmoney
The monthly price AT THIS NODE — the same plan can cost differently elsewhere.
imagesarray
Everything bootable or installable.
images[].shastring
The image's ONLY identifier — carts, reinstalls and ISO attaches all take it.
images[].namestring
Human name (Debian 13).
images[].kindenum
A disk image provisions directly; an iso is an installer you boot from.
One of:diskiso
images[].os_familyenum
For your UI's grouping and icons.
One of:linuxwindowsmikrotik
images[].min_disk_gbint
A reinstall onto a smaller disk is refused — grow the disk first.
months_minint
Shortest term a new VM may be bought for.
Sample response{
"nodes": [
{"node_id": "de1", "label": "Frankfurt", "region": "eu", "country": "DE", "available": true,
"plans": [
{"plan_code": "s2", "name": "S2", "vcpu": 2, "ram_mb": 4096, "disk_gb": 40,
"traffic_bytes": "2199023255552", "price_usd_month": "8.00"}
]}
],
"images": [
{"sha": "9a1b8c2d7e6f", "name": "Debian 13", "kind": "disk", "os_family": "linux", "min_disk_gb": 10}
],
"months_min": 1,
"months_max": 12
}
https://apiservice.vitamindata.net/api/v1/ListVPSImagesEvery image you may boot or install, by sha.
The sha is what a cart, a reinstall and an ISO attach all take. Nothing else identifies an image.
Request
No parameters — send an empty object, {}.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ListVPSImages \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}'
Response200 · application/json
imagesarray
The catalogue.
images[].shastring
The image's ONLY identifier — carts, reinstalls and ISO attaches all take it.
images[].namestring
Human name (Debian 13).
images[].kindenum
A disk image provisions directly; an iso is an installer you boot from.
One of:diskiso
images[].os_familyenum
For your UI's grouping and icons.
One of:linuxwindowsmikrotik
images[].min_disk_gbint
A reinstall onto a smaller disk is refused — grow the disk first.
Sample response{
"images": [
{"sha": "9a1b8c2d7e6f", "name": "Debian 13", "kind": "disk", "os_family": "linux", "min_disk_gb": 10},
{"sha": "3f4e5d6c7b8a", "name": "Windows Server 2025 installer", "kind": "iso",
"os_family": "windows", "min_disk_gb": 40}
]
}
https://apiservice.vitamindata.net/api/v1/QuoteVPSThe price of a new server, itemised.
Request
cartobjectrequired
The server to price.
cart.node_idstringrequired
Where to create the VM, from the storefront's nodes.
cart.placementstringreserved — do not send
Reserved. On this API node_id always decides where the server is created — send it, and pick the node yourself from the storefront.
One of:auto
cart.plan_codestringrequired
The plan, from the chosen node's own price list — plans and prices differ per node.
cart.image_shastringrequired
What to boot or install, by sha. Disk images provision directly; an installer ISO comes attached with the VM set to boot from it.
cart.namestringrequired
The VM's hostname / label.
cart.monthsintrequired
The initial term, within the storefront's months bounds.
cart.extra_disk_gbintoptional
Extra disk beyond the plan's, in GB.
cart.extra_ipsintoptional
Additional public IPv4 addresses.
cart.extra_traffic_tbmoneyoptional
Extra monthly traffic in TB, as a decimal string ("0.5").
Example requestcurl https://apiservice.vitamindata.net/api/v1/QuoteVPS \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"cart":{"node_id":"de1","plan_code":"s2","image_sha":"9a1b8c2d7e6f","months":2,"name":"web-1","extra_disk_gb":20,"extra_ips":1,"extra_traffic_tb":"0.5"}}'
Response200 · application/json
quoteobject
The itemised price. Nothing is created and nothing is charged.
quote.model_namestring
Which pricing model answered.
quote.model_typestring
The model's engine version.
quote.base_usdmoney
The price before discounts and surcharges.
quote.total_usdmoney
The final price — what a sale with this cart charges.
quote.linesarray
The itemisation, signed, summing exactly to the total.
quote.lines[].codestring
What this row is (base, a discount code, a surcharge…).
quote.lines[].kindstring
The row's category, for grouping in your UI.
quote.lines[].amount_usdmoney
Signed. Discounts are negative; the rows sum exactly to total_usd.
quote.lines[].pctstring
The percentage behind the row, when there is one.
quote.cappedbool
The total hit the model's ceiling.
quote.floor_appliedbool
The total was raised to the model's floor.
quote.clampedenum
Set when a cart value was clamped into bounds before pricing.
One of:minmax
quote.invalidstring
Non-empty means the cart cannot be priced — show it and NEVER charge such a quote.
quote.metamap
Model extras, string→string (e.g. an upgrade's remaining_days).
Sample response{
"quote": {
"model_name": "vps_plan",
"model_type": "vps_plan_v1",
"base_usd": "16.00",
"total_usd": "16.00",
"lines": [
{"code": "plan_s2", "kind": "base", "amount_usd": "16.00"}
],
"meta": {"months": "2"}
}
}
POST
CreateVPSOrder
buyIdempotency-Key
https://apiservice.vitamindata.net/api/v1/CreateVPSOrderBuys and provisions a server.
Poll GetOrder for delivery, then GetVPS for the machine.
Request
cartobjectrequired
What to create — the same shape QuoteVPS prices.
cart.node_idstringrequired
Where to create the VM, from the storefront's nodes.
cart.placementstringreserved — do not send
Reserved. On this API node_id always decides where the server is created — send it, and pick the node yourself from the storefront.
One of:auto
cart.plan_codestringrequired
The plan, from the chosen node's own price list — plans and prices differ per node.
cart.image_shastringrequired
What to boot or install, by sha. Disk images provision directly; an installer ISO comes attached with the VM set to boot from it.
cart.namestringrequired
The VM's hostname / label.
cart.monthsintrequired
The initial term, within the storefront's months bounds.
cart.extra_disk_gbintoptional
Extra disk beyond the plan's, in GB.
cart.extra_ipsintoptional
Additional public IPv4 addresses.
cart.extra_traffic_tbmoneyoptional
Extra monthly traffic in TB, as a decimal string ("0.5").
fundingenumrequired
How to pay — see Paying for things. There is no default: omitting it is refused.
One of:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyoptional
Confirmation guard. If set and our fresh quote differs, the sale is refused with price_changed instead of charging a number your customer never saw.
Example requestcurl https://apiservice.vitamindata.net/api/v1/CreateVPSOrder \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"cart":{"node_id":"de1","plan_code":"s2","image_sha":"9a1b8c2d7e6f","months":2,"name":"web-1","extra_disk_gb":20,"extra_ips":1,"extra_traffic_tb":"0.5"},"funding":"FUNDING_AUTO","expected_total_usd":"36.00"}'
Response200 · application/json
orderobject
The order — poll GetOrder until its status is delivered.
order.order_idstring
The order's public id (ord_…).
order.productenum
What was bought.
One of:vpnvps
order.kindstring
The purchase shape: new, extend, upgrade…
order.statusenum
The lifecycle. delivered is the goal; needs_operator means the money is in and a human is finishing delivery — do not re-buy; expired means the invoice lapsed unpaid.
One of:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum
Which rail actually funded it. FUNDING_AUTO resolves to one of these.
One of:invoicebalance
order.total_usdmoney
What the order charges.
order.invoice_idstring
The invoice behind it — every order has one, whichever rail funded it.
order.itemsint
How many entitlements the order mints or extends.
order.created_atunix
When it was placed.
order.delivered_atunix
When delivery finished. Absent until then.
order.breakdownobject
The quote the customer agreed to, verbatim — the same shape Quote returns.
invoiceobject
The invoice behind the order: payable when payment_required, already settled when completed.
invoice.invoice_idstring
The gateway's invoice id (inv_…).
invoice.statusenum
pending is payable. Everything from confirmed through delivered_redirected means the money is irreversibly in — treat all of those as PAID. expired means the link lapsed unpaid.
One of:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring
The hosted payment page. Send your customer here; every rail (coins, chains, balance) lives behind it.
invoice.pay_telegram_urlstring
The same invoice, payable inside Telegram: it opens the payment provider's own bot, which shows the amount and takes the payment there. Offer it beside pay_url for customers who would rather not leave the app. May be absent — only a payment provider with a bot configured has one, so never make it your only pay button.
invoice.price_usdmoney
What the invoice collects.
invoice.expires_atunix
When the payment window closes.
paidbool
The money is captured. Absent (= false) with payment_required.
statusenum
THE field to branch on — see Paying for things.
One of:completedpayment_required
Sample response{
"order": {
"order_id": "ord_2f8k3j", "product": "vps", "kind": "new",
"status": "invoiced", "funding": "invoice", "total_usd": "16.00",
"invoice_id": "inv_7h4w9s", "items": 1, "created_at": "1785412800"
},
"invoice": {
"invoice_id": "inv_7h4w9s", "status": "pending",
"pay_url": "https://pay.example.com/i/inv_7h4w9s",
"price_usd": "16.00", "expires_at": "1785499200"
},
"status": "payment_required"
}
https://apiservice.vitamindata.net/api/v1/QuoteVPSExtendWhat renewing a server costs.
Request
vps_idstringrequired
The server's id, from ListVPS.
monthsintrequired
How many months to add. The storefront's months_min…months_max are what your UI should offer, but a renewal does NOT clamp to them — send a sane number, because whatever you send is what gets priced and charged.
Example requestcurl https://apiservice.vitamindata.net/api/v1/QuoteVPSExtend \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vps_id":"vm_7q3k1n","months":1}'
Response200 · application/json
quoteobject
The itemised price. Nothing is created and nothing is charged.
quote.model_namestring
Which pricing model answered.
quote.model_typestring
The model's engine version.
quote.base_usdmoney
The price before discounts and surcharges.
quote.total_usdmoney
The final price — what a sale with this cart charges.
quote.linesarray
The itemisation, signed, summing exactly to the total.
quote.lines[].codestring
What this row is (base, a discount code, a surcharge…).
quote.lines[].kindstring
The row's category, for grouping in your UI.
quote.lines[].amount_usdmoney
Signed. Discounts are negative; the rows sum exactly to total_usd.
quote.lines[].pctstring
The percentage behind the row, when there is one.
quote.cappedbool
The total hit the model's ceiling.
quote.floor_appliedbool
The total was raised to the model's floor.
quote.clampedenum
Set when a cart value was clamped into bounds before pricing.
One of:minmax
quote.invalidstring
Non-empty means the cart cannot be priced — show it and NEVER charge such a quote.
quote.metamap
Model extras, string→string (e.g. an upgrade's remaining_days).
Sample response{
"quote": {
"model_name": "vps_plan",
"model_type": "vps_plan_v1",
"base_usd": "16.00",
"total_usd": "16.00",
"lines": [
{"code": "plan_s2", "kind": "base", "amount_usd": "16.00"}
],
"meta": {"months": "2"}
}
}
POST
ExtendVPS
buyIdempotency-Key
https://apiservice.vitamindata.net/api/v1/ExtendVPSRenews a server.
Renewing early costs nothing extra: the new expiry is measured from the current one, not from today.
Request
vps_idstringrequired
The server's id, from ListVPS.
monthsintrequired
How many months to add. The storefront's months_min…months_max are what your UI should offer, but a renewal does NOT clamp to them — send a sane number, because whatever you send is what gets priced and charged.
fundingenumrequired
How to pay — see Paying for things. There is no default: omitting it is refused.
One of:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyoptional
Confirmation guard. If set and our fresh quote differs, the sale is refused with price_changed instead of charging a number your customer never saw.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ExtendVPS \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"vps_id":"vm_7q3k1n","months":1,"funding":"FUNDING_AUTO","expected_total_usd":"8.00"}'
Response200 · application/json
orderobject
The order — poll GetOrder until its status is delivered.
order.order_idstring
The order's public id (ord_…).
order.productenum
What was bought.
One of:vpnvps
order.kindstring
The purchase shape: new, extend, upgrade…
order.statusenum
The lifecycle. delivered is the goal; needs_operator means the money is in and a human is finishing delivery — do not re-buy; expired means the invoice lapsed unpaid.
One of:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum
Which rail actually funded it. FUNDING_AUTO resolves to one of these.
One of:invoicebalance
order.total_usdmoney
What the order charges.
order.invoice_idstring
The invoice behind it — every order has one, whichever rail funded it.
order.itemsint
How many entitlements the order mints or extends.
order.created_atunix
When it was placed.
order.delivered_atunix
When delivery finished. Absent until then.
order.breakdownobject
The quote the customer agreed to, verbatim — the same shape Quote returns.
invoiceobject
The invoice behind the order: payable when payment_required, already settled when completed.
invoice.invoice_idstring
The gateway's invoice id (inv_…).
invoice.statusenum
pending is payable. Everything from confirmed through delivered_redirected means the money is irreversibly in — treat all of those as PAID. expired means the link lapsed unpaid.
One of:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring
The hosted payment page. Send your customer here; every rail (coins, chains, balance) lives behind it.
invoice.pay_telegram_urlstring
The same invoice, payable inside Telegram: it opens the payment provider's own bot, which shows the amount and takes the payment there. Offer it beside pay_url for customers who would rather not leave the app. May be absent — only a payment provider with a bot configured has one, so never make it your only pay button.
invoice.price_usdmoney
What the invoice collects.
invoice.expires_atunix
When the payment window closes.
paidbool
The money is captured. Absent (= false) with payment_required.
statusenum
THE field to branch on — see Paying for things.
One of:completedpayment_required
Sample response{
"order": {
"order_id": "ord_5d1p8m", "product": "vps", "kind": "extend",
"status": "paid", "funding": "balance", "total_usd": "8.00",
"invoice_id": "inv_1c6v3z", "items": 1, "created_at": "1785412800"
},
"invoice": {
"invoice_id": "inv_1c6v3z", "status": "confirmed", "price_usd": "8.00"
},
"paid": true,
"status": "completed"
}
https://apiservice.vitamindata.net/api/v1/QuoteVPSUpgradeWhat a bigger shape costs, pro-rated over the time already paid for.
Request
vps_idstringrequired
The server's id, from ListVPS.
specobjectrequired
The TARGET shape. Omitted/zero fields keep their current value.
spec.vcpuintoptional
Target cores. 0 keeps the current value.
spec.ram_mbintoptional
Target memory in MB. 0 keeps the current value.
spec.disk_gbintoptional
Target disk in GB. Disk only grows — a smaller value is refused, because shrinking a filesystem under an OS is data loss.
Example requestcurl https://apiservice.vitamindata.net/api/v1/QuoteVPSUpgrade \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"vps_id":"vm_7q3k1n","spec":{"vcpu":4,"ram_mb":8192,"disk_gb":80}}'
Response200 · application/json
quoteobject
The itemised price. Nothing is created and nothing is charged.
quote.model_namestring
Which pricing model answered.
quote.model_typestring
The model's engine version.
quote.base_usdmoney
The price before discounts and surcharges.
quote.total_usdmoney
The final price — what a sale with this cart charges.
quote.linesarray
The itemisation, signed, summing exactly to the total.
quote.lines[].codestring
What this row is (base, a discount code, a surcharge…).
quote.lines[].kindstring
The row's category, for grouping in your UI.
quote.lines[].amount_usdmoney
Signed. Discounts are negative; the rows sum exactly to total_usd.
quote.lines[].pctstring
The percentage behind the row, when there is one.
quote.cappedbool
The total hit the model's ceiling.
quote.floor_appliedbool
The total was raised to the model's floor.
quote.clampedenum
Set when a cart value was clamped into bounds before pricing.
One of:minmax
quote.invalidstring
Non-empty means the cart cannot be priced — show it and NEVER charge such a quote.
quote.metamap
Model extras, string→string (e.g. an upgrade's remaining_days).
restart_requiredbool
Applying this shape needs a power cycle — a customer should learn that BEFORE paying.
monthly_before_usdmoney
The recurring price today.
monthly_after_usdmoney
The recurring price after the upgrade — what renewals will cost from now on.
Sample response{
"quote": {
"model_name": "vps_upgrade",
"model_type": "vps_plan_v1",
"base_usd": "4.20",
"total_usd": "4.20",
"lines": [
{"code": "prorate_vcpu", "kind": "vps_upgrade", "amount_usd": "2.40"},
{"code": "prorate_ram", "kind": "vps_upgrade", "amount_usd": "1.80"}
],
"meta": {"remaining_days": "21", "monthly_delta_usd": "6.00", "quote_expires_at": "1785416400"}
},
"restart_required": true,
"monthly_before_usd": "8.00",
"monthly_after_usd": "14.00"
}
POST
UpgradeVPS
buyIdempotency-Key
https://apiservice.vitamindata.net/api/v1/UpgradeVPSPays for and applies a bigger shape. Disk can only grow.
Request
vps_idstringrequired
The server's id, from ListVPS.
specobjectrequired
The TARGET shape — quote it first; the quote also tells you about the reboot.
spec.vcpuintoptional
Target cores. 0 keeps the current value.
spec.ram_mbintoptional
Target memory in MB. 0 keeps the current value.
spec.disk_gbintoptional
Target disk in GB. Disk only grows — a smaller value is refused, because shrinking a filesystem under an OS is data loss.
fundingenumrequired
How to pay — see Paying for things. There is no default: omitting it is refused.
One of:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyoptional
Confirmation guard. If set and our fresh quote differs, the sale is refused with price_changed instead of charging a number your customer never saw.
Example requestcurl https://apiservice.vitamindata.net/api/v1/UpgradeVPS \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"vps_id":"vm_7q3k1n","spec":{"vcpu":4,"ram_mb":8192,"disk_gb":80},"funding":"FUNDING_AUTO","expected_total_usd":"4.20"}'
Response200 · application/json
orderobject
The order — poll GetOrder until its status is delivered.
order.order_idstring
The order's public id (ord_…).
order.productenum
What was bought.
One of:vpnvps
order.kindstring
The purchase shape: new, extend, upgrade…
order.statusenum
The lifecycle. delivered is the goal; needs_operator means the money is in and a human is finishing delivery — do not re-buy; expired means the invoice lapsed unpaid.
One of:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum
Which rail actually funded it. FUNDING_AUTO resolves to one of these.
One of:invoicebalance
order.total_usdmoney
What the order charges.
order.invoice_idstring
The invoice behind it — every order has one, whichever rail funded it.
order.itemsint
How many entitlements the order mints or extends.
order.created_atunix
When it was placed.
order.delivered_atunix
When delivery finished. Absent until then.
order.breakdownobject
The quote the customer agreed to, verbatim — the same shape Quote returns.
invoiceobject
The invoice behind the order: payable when payment_required, already settled when completed.
invoice.invoice_idstring
The gateway's invoice id (inv_…).
invoice.statusenum
pending is payable. Everything from confirmed through delivered_redirected means the money is irreversibly in — treat all of those as PAID. expired means the link lapsed unpaid.
One of:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring
The hosted payment page. Send your customer here; every rail (coins, chains, balance) lives behind it.
invoice.pay_telegram_urlstring
The same invoice, payable inside Telegram: it opens the payment provider's own bot, which shows the amount and takes the payment there. Offer it beside pay_url for customers who would rather not leave the app. May be absent — only a payment provider with a bot configured has one, so never make it your only pay button.
invoice.price_usdmoney
What the invoice collects.
invoice.expires_atunix
When the payment window closes.
paidbool
The money is captured. Absent (= false) with payment_required.
statusenum
THE field to branch on — see Paying for things.
One of:completedpayment_required
Sample response{
"order": {
"order_id": "ord_5d1p8m", "product": "vps", "kind": "extend",
"status": "paid", "funding": "balance", "total_usd": "8.00",
"invoice_id": "inv_1c6v3z", "items": 1, "created_at": "1785412800"
},
"invoice": {
"invoice_id": "inv_1c6v3z", "status": "confirmed", "price_usd": "8.00"
},
"paid": true,
"status": "completed"
}
Managing servers
Every verb here takes the server by id — the field is literally named id on these calls, unlike the money verbs' vps_id.
https://apiservice.vitamindata.net/api/v1/ListVPSYour machines, with power state and addresses.
Request
limitintoptional
Page size. Default 50.
cursorcursoroptional
The previous response's next_cursor. Omit it for the first page.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ListVPS \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"limit":50,"cursor":""}'
Response200 · application/json
vps[].idstring
The server's id — what every management verb's id and every money verb's vps_id take.
vps[].namestring
Its hostname / label.
vps[].node_idstring
Where it runs.
vps[].lifecycleenum
0 provisioning · 1 active · 2 suspended · 3 deleting · 4 deleted.
One of:01234
vps[].provisionedbool
The machine exists on its host.
vps[].power_desiredenum
What the power SHOULD be: 1 on, 0/absent off. The live state is GetVPSStats.running.
One of:01
vps[].mem_mbint
Memory in MB.
vps[].disk_gbint
Disk in GB.
vps[].image_shastring
What it booted or installed from.
vps[].expires_atunix
When the server lapses — renew with ExtendVPS before this.
vps[].created_atunix
When it was created.
vps[].ipsarray
Its public addresses.
vps[].private_ipstring
Its private address, when the plan has one.
next_cursorcursor
Pass it back as cursor for the next page. Absent/empty = you have everything.
Sample response{
"vps": [{
"id": "vm_7q3k1n",
"name": "web-1",
"node_id": "de1",
"lifecycle": 1,
"provisioned": true,
"power_desired": 1,
"vcpu": 2,
"mem_mb": 4096,
"disk_gb": 40,
"image_sha": "9a1b8c2d7e6f",
"expires_at": "1793188800",
"created_at": "1785000000",
"ips": ["203.0.113.10"],
"private_ip": "10.77.0.10"
}]
}
https://apiservice.vitamindata.net/api/v1/GetVPSOne machine in detail.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetVPS \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n"}'
Response200 · application/json
vps.idstring
The server's id — what every management verb's id and every money verb's vps_id take.
vps.namestring
Its hostname / label.
vps.node_idstring
Where it runs.
vps.lifecycleenum
0 provisioning · 1 active · 2 suspended · 3 deleting · 4 deleted.
One of:01234
vps.provisionedbool
The machine exists on its host.
vps.power_desiredenum
What the power SHOULD be: 1 on, 0/absent off. The live state is GetVPSStats.running.
One of:01
vps.mem_mbint
Memory in MB.
vps.disk_gbint
Disk in GB.
vps.image_shastring
What it booted or installed from.
vps.expires_atunix
When the server lapses — renew with ExtendVPS before this.
vps.created_atunix
When it was created.
vps.ipsarray
Its public addresses.
vps.private_ipstring
Its private address, when the plan has one.
livebool
Read from the plane just now.
Sample response{
"vps": {
"id": "vm_7q3k1n",
"name": "web-1",
"node_id": "de1",
"lifecycle": 1,
"provisioned": true,
"power_desired": 1,
"vcpu": 2,
"mem_mb": 4096,
"disk_gb": 40,
"image_sha": "9a1b8c2d7e6f",
"expires_at": "1793188800",
"created_at": "1785000000",
"ips": ["203.0.113.10"],
"private_ip": "10.77.0.10"
},
"live": true
}
https://apiservice.vitamindata.net/api/v1/GetVPSStatsLive CPU, memory, disk and network.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetVPSStats \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n"}'
Response200 · application/json
cpu_pctint
CPU load, percent.
mem_used_mbint
Memory in use, MB.
disk_used_mbint
Disk in use, MB.
rx_bpsint64
Inbound, bits per second.
tx_bpsint64
Outbound, bits per second.
runningbool
The machine is powered on right now.
updated_atunix
When these figures were sampled.
Sample response{
"cpu_pct": 12,
"mem_used_mb": 1536,
"disk_used_mb": 9216,
"rx_bps": "1048576",
"tx_bps": "524288",
"running": true,
"updated_at": "1785412790"
}
https://apiservice.vitamindata.net/api/v1/GetVPSUsageTraffic used against the machine's allowance, per bundle.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
Example requestcurl https://apiservice.vitamindata.net/api/v1/GetVPSUsage \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n"}'
Response200 · application/json
total_downbytes
Lifetime download.
total_upbytes
Lifetime upload.
bundlesarray
The traffic bundles, with current marking the one draining now.
bundles[].idint64
The traffic bundle's id on the compute plane.
bundles[].modeint
The plane's accounting mode code. Treat as opaque.
bundles[].bytes_totalbytes
The bundle's full allowance.
bundles[].used_dlbytes
Downloaded against it.
bundles[].used_upbytes
Uploaded against it.
bundles[].stateint
The plane's state code. Treat as opaque.
bundles[].currentbool
This is the bundle draining right now.
bundles[].expires_atunix
When the bundle lapses.
Sample response{
"total_down": "53687091200",
"total_up": "10737418240",
"bundles": [
{"id": "41", "mode": 1, "bytes_total": "2199023255552",
"used_dl": "53687091200", "used_up": "10737418240",
"state": 1, "current": true, "expires_at": "1793188800"}
]
}
https://apiservice.vitamindata.net/api/v1/VPSPowerPower control.
shutdown asks the OS; force_stop pulls the plug. Prefer the first.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
actionenumrequired
shutdown/reboot are graceful; reset/force_stop are the power button.
One of:startshutdownrebootresetforce_stop
Example requestcurl https://apiservice.vitamindata.net/api/v1/VPSPower \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n","action":"reboot"}'
Response200 · application/json
okbool
The plane accepted the action. Watch GetVPSStats for the machine's actual state.
Sample response{"ok": true}
https://apiservice.vitamindata.net/api/v1/ReinstallVPSWipes the disk and installs a fresh image.
Destructive and NOT retry-safe — one call, one reinstall. The image must fit the current disk; grow it first if not.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
image_shastringrequired
The image, by sha from ListVPSImages. Nothing else names an image, and an unoffered sha is refused.
reset_rootbooloptional
Also mint a fresh root password.
Example requestcurl https://apiservice.vitamindata.net/api/v1/ReinstallVPS \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n","image_sha":"9a1b8c2d7e6f","reset_root":true}'
Response200 · application/json
okbool
The plane accepted the action. Watch GetVPSStats for the machine's actual state.
Sample response{"ok": true}
https://apiservice.vitamindata.net/api/v1/AttachVPSISOAttaches an installer ISO. Pair it with a boot order of 1 to boot from it.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
image_shastringrequired
The image, by sha from ListVPSImages. Nothing else names an image, and an unoffered sha is refused.
Example requestcurl https://apiservice.vitamindata.net/api/v1/AttachVPSISO \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n","image_sha":"3f4e5d6c7b8a"}'
Response200 · application/json
okbool
The plane accepted the action. Watch GetVPSStats for the machine's actual state.
Sample response{"ok": true}
https://apiservice.vitamindata.net/api/v1/DetachVPSISORemoves the ISO and returns to booting from disk.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
Example requestcurl https://apiservice.vitamindata.net/api/v1/DetachVPSISO \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n"}'
Response200 · application/json
okbool
The plane accepted the action. Watch GetVPSStats for the machine's actual state.
Sample response{"ok": true}
POST
SetVPSBootOrder
manage
https://apiservice.vitamindata.net/api/v1/SetVPSBootOrderWhich device boots first.
Request
idstringrequired
The server's id, from ListVPS. Note the field is id on the management verbs — only the money verbs spell it vps_id.
orderenumrequired
0 disk first, 1 CD-ROM first.
One of:01
Example requestcurl https://apiservice.vitamindata.net/api/v1/SetVPSBootOrder \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"id":"vm_7q3k1n","order":1}'
Response200 · application/json
okbool
The plane accepted the action. Watch GetVPSStats for the machine's actual state.
Sample response{"ok": true}