Справочник API Vitamin

Продавайте VPN-аккаунты и виртуальные серверы со своего сайта, бота или скрипта и управляйте ими.

Базовый URLhttps://apiservice.vitamindata.net/api/v1

Ключи создаются в вашей панели. Если раздела нет, попросите поддержку включить доступ к API для вашего аккаунта.

1

Создайте API-ключ в панели и отправляйте его как bearer-токен в каждом вызове.

2

Вызовите Ping, чтобы проверить ключ, затем получите свои цены через ListPlans и GetVPSStorefront.

3

Продавайте с FUNDING_AUTO: когда баланса хватает, платит он; когда нет — клиент получает ссылку на оплату.

Аутентификация

Каждый запрос несёт ваш ключ как bearer-токен. На этом хосте нет cookie и не нужно получать CSRF-токен — ключ и есть все учётные данные.

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Ключи создаются в вашей панели, в разделе API. Секрет показывается один раз, при создании: мы храним только его хеш. Если он потерян, решение — ротация ключа: она выдаёт новый секрет и оставляет старый рабочим ещё на сутки, чтобы вы развернули изменения без простоя.

Ключ можно ограничить списком исходных адресов, дать ему собственный лимит запросов в минуту и отобрать у него отдельные операции. Это настраивают наши операторы — напишите в поддержку, если нужен ключ, который, скажем, может покупать, но никогда не может удалять услуги.

Тестовые ключи

Ключ, начинающийся с sk_test_, читает реальные данные, но отклоняет всё, что тратит деньги или затрагивает реальную машину, — так вы соберёте и проверите интеграцию раньше, чем она сможет что-то стоить.

Как выглядит отказ

Неизвестный ключ и ключ аккаунта без доступа к API получают один и тот же 401, слово в слово: ответ никогда не подтверждает, существует ли ключ. Исключение — ваш собственный ключ, переживший срок перекрытия при ротации: он говорит api key expired, потому что вы и так знаете, что этот ключ был настоящим, и вам нужно понять, почему он перестал работать. Повторяющиеся отказы с одного адреса ограничиваются — см. ограничение частоты.

Оплата

Всё, что вы покупаете — VPN-аккаунт, продление, сервер, продление сервера, апгрейд — проходит по одному контракту. Вы выбираете, откуда берутся деньги:

fundingЧто происходит
FUNDING_AUTOРекомендуется. Списывает с баланса, если баланса хватает; иначе вызов всё равно успешен и возвращает ссылку на оплату. Один вызов, никакой ошибки, которую нужно разбирать.
FUNDING_BALANCEТолько баланс. Если баланса не хватает, вызов ЗАВЕРШАЕТСЯ ОШИБКОЙ insufficient_balance (в ошибке всё равно есть ссылка на оплату).
FUNDING_INVOICEВсегда возвращает ссылку на оплату, даже если баланса хватило бы.

С FUNDING_AUTO вы смотрите на одно поле:

{"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 означает, что деньги списаны и выдача началась — опрашивайте GetOrder, пока статус не станет delivered. payment_required означает: отправьте клиента на pay_url; выдача начнётся сама, когда счёт будет оплачен.

Цены всегда наши. Можно передать expected_total_usd как страховку: если наш свежий расчёт отличается, продажа отклоняется с price_changed и новой суммой, вместо того чтобы списать сумму, которой клиент не видел.

Безопасные повторы

Отправляйте заголовок Idempotency-Key в каждом вызове, который тратит деньги. Если ответ до вас не дошёл — таймаут, разорванное соединение, перезапущенный воркер — повторите ТОТ ЖЕ запрос с ТЕМ ЖЕ ключом и получите исходный результат, а не второе списание.

Idempotency-Key: 8f14e45f-ea6d-4b3a-9c1b-2f0d5a7e91c3

На каждое действие клиента — новый ключ (UUID идеален). Повторное использование ключа с другим телом отклоняется с idempotency_conflict: такое сочетание означает ошибку в коде, и угадывать, какой запрос вы имели в виду, было бы хуже, чем сказать вам об этом.

Ограничение частоты

Каждый ответ на аутентифицированный запрос говорит, где находится ваш ключ:

RateLimit-Limit: 6000
RateLimit-Remaining: 5987
RateLimit-Policy: 6000;w=60

Лимит — на ключ, в минуту, и он задаётся для вашего аккаунта. Значения по умолчанию хватает магазину; загруженному боту стоит попросить больше, а не подстраиваться под значение по умолчанию. При превышении приходит 429 с Retry-After.

429 приходит и тогда, когда много запросов с одного адреса не проходят аутентификацию. Это защита от подбора, а не ваша квота: она снимается сама (в заголовке сказано когда), и рабочий ключ её никогда не вызывает.

Кроме того, на каждом ответе — даже когда ключа в запросе не было — вы увидите семейство X-Ratelimit-*. Это грубый ограничитель НА АДРЕС перед всем API, а не бюджет вашего ключа: держите темп по RateLimit-Remaining, а заголовки X- считайте чужим делом.

Ошибки

Сбои возвращаются как HTTP-статус и JSON-тело. Верхнеуровневый code — транспортная категория; верхнеуровневый message несёт стабильный машинный код. Полные детали — тот же машинный код, безопасная фраза и полезные дополнительные поля — приходят в details, в поле 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"}}]}

У канала ошибок две особенности, и обе стоит учесть в коде: value — это protobuf в base64 (игнорируйте его — читайте debug), а дополнительные поля внутри debug записаны в lowerCamelCase — payUrl, orderId, totalUsd, retryAfterSeconds — соглашение Connect, в отличие от snake_case во всех остальных местах. Ветвитесь по верхнеуровневому message или по debug.code; никогда — по тексту фразы.

Отказы до авторизации запроса

Запрос, который так и не доходит до обработчика — ключа нет или он неверен (401), исходный адрес ключу не разрешён (403), превышена частота (429), аутентификация недоступна (503), — отклоняется на входе, и вход отвечает БОЛЕЕ КОРОТКИМ телом: транспортный code и обычная фраза, без details и без машинного кода.

{"code": "unauthenticated", "message": "invalid api key"}

Поэтому в таких случаях ветвитесь по HTTP-СТАТУСУ (и соблюдайте Retry-After при 429); машинные коды ниже относятся к вызовам, которые дошли до обработчика. Грубый ограничитель на адрес появился ещё раньше и отвечает {"error":"rate_limited"}: поле называется error, а не code.

КодЧто значитЧто делать
forbidden_scopeУ ключа нет нужной области доступа, либо эта операция у него отобрана.Попросите поддержку расширить ключ.
not_foundТакого объекта для этого аккаунта нет.Проверьте идентификатор. Чужой идентификатор отвечает тем же — так и задумано.
invalid_requestПоле заполнено неверно.Исправьте и отправьте снова; повтор без изменений не поможет.
insufficient_balanceОплаты только с баланса не хватило.Используйте payUrl из деталей или перейдите на FUNDING_AUTO.
price_changedВаше значение expected_total_usd больше не совпадает.Запросите цену заново и подтвердите новую сумму с клиентом.
idempotency_conflictЭтот ключ уже использовался с другим телом запроса.Используйте новый ключ на каждое действие.
sandbox_unavailableКлюч sk_test_ попытался потратить деньги или затронуть реальную машину.Так и задумано — для такого вызова используйте боевой ключ. Тестовые ключи читают, но никогда не покупают.
unpriceableЗапрошенная конфигурация не продаётся: тариф или узел без цены либо корзина, которую не покрывает ни одна модель.Перечитайте магазин и запросите расчёт цены перед покупкой: ту же корзину расчёт отклонит так же.
upstream_unavailableОдна из систем, от которых мы зависим, недоступна.Повторяйте с нарастающей задержкой; чтения могут быть ненадолго устаревшими.
order_failedВыдача после оплаты не удалась.Не покупайте повторно. Опрашивайте GetOrder; мы восстанавливаем такие заказы автоматически, и поддержка их видит.
internalНа нашей стороне что-то сломалось, и мы это не классифицировали.Повторите один раз с задержкой; если повторяется — укажите X-Request-Id в обращении в поддержку.

Соглашения

  • Транспорт. Каждый вызов — POST {base}/{Method} с JSON-телом — POST /api/v1/CreateVPNOrder. Больше ничего нет: любой другой HTTP-метод отвечает 405, никакого маппинга на REST-глаголы и никаких параметров в пути.
  • Деньги — это строка. "19.99", никогда 19.99: JSON-число в большинстве языков становится float и не может точно хранить цент.
  • 64-битные целые приходят строками. Каждый счётчик байтов и каждая unix-метка времени — 64-битные, и на проводе они в кавычках — "remaining_bytes": "96636764160". Разбирайте их как целые; в запросах допустима любая из двух форм.
  • Нули опускаются. Поле со значением 0, false или пустым вообще не появляется в ответе. Считайте отсутствие нулём — и помните: дневной лимит 0 означает, что лимита НЕТ, а не «0 ГБ».
  • Время — в unix-секундах, кроме окна транзакций: оно принимает и возвращает RFC3339 или YYYY-MM-DD.
  • Трафик — в байтах, никогда не в гигабайтах, во всех показателях.
  • Идентификаторы непрозрачны. acc_…, ord_…, vpn_…. Никогда не разбирайте и не генерируйте их и не считайте последовательными.
  • Постраничность — по непрозрачному курсору: верните next_cursor из предыдущего ответа. Пустой next_cursor означает, что вы получили всё.
  • В таблицах полей используются короткие обозначения типов. money — точная десятичная строка; unix — unix-секунды (64 бита, поэтому строка); bytes — число байтов (64 бита, поэтому строка); int64 — любое другое 64-битное (строка); int — 32-битное, обычное число; cursor — непрозрачный курсор постраничного вывода; enum — ровно одно из перечисленных значений.
  • Новые поля появляются без предупреждения, а смысл существующих не меняется. Игнорируйте то, чего не знаете.

Начало работы

Первый вызов: он подтверждает, что ключ работает, и говорит, какому аккаунту он принадлежит.

POST

Ping

любой ключ
https://apiservice.vitamindata.net/api/v1/Ping

Возвращает идентификатор вашего аккаунта, тип ключа (боевой или тестовый) и наши часы.

Запрос

Параметров нет — отправьте пустой объект, {}.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/Ping \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
Ответ200 · application/json
account_idstring

Аккаунт ключа — доказательство, что ключ распознан.

modeenum

Какого типа ключ вы прислали.

Одно из:livetest
server_timeunix

Наши часы — полезно, чтобы заметить расхождение времени до того, как оно сломает подписи или окна.

Пример ответа
{
  "account_id": "acc_9f3k2m7q",
  "mode": "live",
  "server_time": "1785412800"
}

Аккаунт и баланс

POST

GetAccount

read
https://apiservice.vitamindata.net/api/v1/GetAccount

Email, статус и язык вашего аккаунта, а также подтверждён ли адрес.

Запрос

Параметров нет — отправьте пустой объект, {}.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetAccount \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
Ответ200 · application/json
accountobject

Ваш аккаунт.

account.account_idstring

Публичный идентификатор (acc_…).

account.emailstring

Адрес для входа.

account.statusstring

active, если аккаунт не ограничен.

account.localestring

Язык аккаунта — на него локализуются названия карточек и уведомления.

account.email_verifiedbool

Адрес подтверждён.

account.created_atunix

Когда аккаунт был создан.

Пример ответа
{
  "account": {
    "account_id": "acc_9f3k2m7q",
    "email": "dev@example.com",
    "status": "active",
    "locale": "en",
    "email_verified": true,
    "created_at": "1769000000"
  }
}
POST

GetBalance

read
https://apiservice.vitamindata.net/api/v1/GetBalance

Баланс по вашей книге и сумма, которую покупка действительно может списать.

available_usd — то число, на которое надо смотреть перед покупкой: оно не включает суммы, уже заблокированные незавершённым заказом.

Запрос

Параметров нет — отправьте пустой объект, {}.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetBalance \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
Ответ200 · application/json
balance_usdmoney

Полный баланс по книге.

available_usdmoney

Баланс минус блокировки — то, что покупка может потратить прямо сейчас.

as_ofstring

Метка времени этих цифр по книге, RFC3339.

Пример ответа
{
  "balance_usd": "72.60",
  "available_usd": "60.70",
  "as_of": "2026-07-29T12:00:00Z"
}
POST

ListTransactions

read
https://apiservice.vitamindata.net/api/v1/ListTransactions

Ваша книга, сначала новые.

По умолчанию — последние три месяца. Окно шире 92 дней сужается, и ответ сообщает, какое окно он действительно использовал, — так короткий ответ никогда не бывает двусмысленным.

Запрос
limitintнеобязательно

Размер страницы. По умолчанию 25, максимум 100.

cursorcursorнеобязательно

next_cursor из предыдущего ответа. Для первой страницы опустите.

kindstringнеобязательно

Необязательный фильтр по значениям kind ниже, через запятую.

fromstringнеобязательно

Начало окна, RFC3339 или YYYY-MM-DD.

tostringнеобязательно

Конец окна. to в виде только даты включает весь этот день.

Пример запроса
curl 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"}'
Ответ200 · application/json
transactionsarray

Строки книги.

transactions[].idstring

Идентификатор строки книги.

transactions[].tsstring

Когда, RFC3339.

transactions[].kindenum

Что двигало деньги. topup_credit — оплаченное пополнение; два вида invoice_debit_* — покупки. Внутренние блокировка и освобождение средств по незавершённому заказу в эту ленту не попадают.

Одно из:topup_creditexternal_creditinvoice_debit_reservedinvoice_debit_externaloverpay_creditmanual_creditmanual_debitspend_debitspend_refundautomated_correction
transactions[].amount_usdmoney

Со знаком — отрицательная при списаниях.

transactions[].balance_after_usdmoney

Текущий баланс после этой строки.

transactions[].ref_invoice_idstring

Счёт за движением — передайте его в GetInvoice, чтобы получить полную картину.

transactions[].descriptionstring

Короткая человекочитаемая подпись. Только для отображения; никогда не ветвитесь по ней.

next_cursorcursor

Верните его как cursor, чтобы получить следующую страницу. Отсутствует/пустой = вы получили всё.

has_morebool

За этой страницей есть ещё строки.

fromstring

ФАКТИЧЕСКИ применённое окно (RFC3339). Уже, чем вы просили, ⇒ вы упёрлись в предел в 92 дня.

tostring

Конец применённого окна.

Пример ответа
{
  "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/CreateTopup

Создаёт счёт к оплате, который пополняет ваш баланс.

Отправьте клиента (или себя) на invoice.pay_url. Баланс меняется после оплаты.

Запрос
amount_usdmoneyобязательное

Сколько добавить, десятичной строкой.

Пример запроса
curl 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"}'
Ответ200 · application/json
invoiceobject

Счёт к оплате.

invoice.invoice_idstring

Идентификатор счёта в шлюзе (inv_…).

invoice.statusenum

pending — можно оплачивать. Всё от confirmed до delivered_redirected означает, что деньги пришли необратимо — считайте все эти статусы ОПЛАЧЕННЫМИ. expired означает, что ссылка истекла неоплаченной.

Одно из:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

Размещённая у нас страница оплаты. Отправляйте клиента сюда; за ней живут все способы оплаты (монеты, сети, баланс).

invoice.pay_telegram_urlstring

Тот же счёт, оплачиваемый прямо в Telegram: ссылка открывает бот самого платёжного провайдера, который показывает сумму и там же принимает оплату. Предлагайте её рядом с pay_url тем, кто предпочитает не выходить из приложения. Может отсутствовать — она есть только у платёжного провайдера с настроенным ботом, поэтому никогда не делайте её единственной кнопкой оплаты.

invoice.price_usdmoney

Сумма, которую собирает счёт.

invoice.expires_atunix

Когда закрывается окно оплаты.

Пример ответа
{
  "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"
  }
}
POST

GetInvoice

read
https://apiservice.vitamindata.net/api/v1/GetInvoice

Один платёж полностью, включая то, что видно в блокчейне.

Ключ связи — ref_invoice_id из строки книги. Читать можно только счета, созданные вашим аккаунтом.

Запрос
invoice_idstringобязательное

Из ref_invoice_id строки книги, из заказа или из пополнения.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetInvoice \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"invoice_id":"inv_5k8p2q"}'
Ответ200 · application/json
invoiceobject

Сам счёт.

invoice.invoice_idstring

Идентификатор счёта в шлюзе (inv_…).

invoice.statusenum

pending — можно оплачивать. Всё от confirmed до delivered_redirected означает, что деньги пришли необратимо — считайте все эти статусы ОПЛАЧЕННЫМИ. expired означает, что ссылка истекла неоплаченной.

Одно из:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

Размещённая у нас страница оплаты. Отправляйте клиента сюда; за ней живут все способы оплаты (монеты, сети, баланс).

invoice.pay_telegram_urlstring

Тот же счёт, оплачиваемый прямо в Telegram: ссылка открывает бот самого платёжного провайдера, который показывает сумму и там же принимает оплату. Предлагайте её рядом с pay_url тем, кто предпочитает не выходить из приложения. Может отсутствовать — она есть только у платёжного провайдера с настроенным ботом, поэтому никогда не делайте её единственной кнопкой оплаты.

invoice.price_usdmoney

Сумма, которую собирает счёт.

invoice.expires_atunix

Когда закрывается окно оплаты.

paymentsarray

Что видно в блокчейне. Пусто для счёта, оплаченного с баланса (блокчейн не участвовал), и для счёта, который ещё никто не оплатил, — пустой список не ошибка.

payments[].chainstring

Сеть, по которой пришёл платёж (tron, bsc, …).

payments[].assetstring

Чем заплатили (USDT, …).

payments[].amountmoney

Сумма в активе, точная.

payments[].tx_hashstring

Транзакция в блокчейне — доказательство оплаты для вашего клиента.

payments[].confirmedbool

Блокчейн его финализировал.

payments[].seen_atunix

Когда мы впервые его увидели.

order_idstring

Что купил счёт. Отсутствует у пополнения — оно ничего не покупает.

Пример ответа
{
  "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"
}

Цены

Здесь ничего не создаётся — считайте цену сколько угодно раз, пока клиент не принял решение.

POST

ListPlans

read
https://apiservice.vitamindata.net/api/v1/ListPlans

Что вы можете продавать: границы ползунка и, если ваш магазин их использует, карточки с фиксированной ценой.

Показывайте то, что заполнено. Карточка покупается передачей её bundle_id в корзину; корзина-ползунок использует гб/месяцы/пользователи.

Запрос

Параметров нет — отправьте пустой объект, {}.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/ListPlans \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
Ответ200 · application/json
model_namestring

Модель ценообразования вашего магазина.

model_typestring

Версия её движка.

boundsobject

Правила конфигуратора — каждый расчёт и каждый заказ перепроверяет их на стороне сервера.

bounds.gb_minint

Минимальный трафик, который может запросить корзина.

bounds.gb_maxint

Максимальный.

bounds.gb_stepint

Шаг ползунка.

bounds.users_minint

Минимум одновременных устройств.

bounds.users_maxint

Максимум.

bounds.months_minint

Минимальный срок.

bounds.months_maxint

Максимальный.

bounds.new_accounts_maxint

Максимум аккаунтов, которые может создать один заказ.

bounds.extend_maxint

Максимум аккаунтов, которые может продлить один заказ.

bounds.default_gbint

Разумное значение ползунка по умолчанию.

bounds.default_usersint

Устройств по умолчанию.

bounds.default_monthsint

Срок по умолчанию.

bundlesarray

Карточки с фиксированной ценой, если ваш магазин — каталог карточек.

bundles[].bundle_idstring

Идентификатор, который кладут в cart.bundle_id.

bundles[].namestring

Название карточки, уже локализованное под язык аккаунта.

bundles[].gbint

Включённый трафик.

bundles[].monthsint

Срок действия.

bundles[].online_usersint

Одновременных устройств.

bundles[].price_usdmoney

Цена. Это И ЕСТЬ цена — для карточки расчёт не нужен.

bundles[].highlightbool

Рекомендуемая карточка магазина.

bundles[].daily_cap_gbint

Дневной предел в ГБ. Отсутствует = предела нет.

Пример ответа
{
  "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}
  ]
}
POST

Quote

read
https://apiservice.vitamindata.net/api/v1/Quote

Итоговая цена VPN-корзины, по позициям. Скидки уже применены.

Запрос
cartobjectобязательное

Корзина для расчёта цены.

cart.kindenumобязательное

Купить новые аккаунты или добавить трафик и время существующим.

Одно из:newextend
cart.gbintнеобязательно

Трафик на аккаунт, в ГБ, в границах из ListPlans.

cart.monthsintнеобязательно

Срок действия на аккаунт, в месяцах.

cart.usersintнеобязательно

Одновременных устройств на аккаунт.

cart.new_accountsintнеобязательно

Только для kind:"new": сколько аккаунтов создать. Имена пользователей генерирует сервер.

cart.extend_vpn_idsarrayнеобязательно

Только для kind:"extend": какие аккаунты продлить, по публичным идентификаторам.

cart.bundle_idstringнеобязательно

Покупает карточку с фиксированной ценой из ListPlans.bundles вместо настраиваемой корзины. Если задано, гб/месяцы/пользователи игнорируются — действуют значения и цена самой карточки.

Пример запроса
curl 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}}'
Другие формы этого запроса
Продлить аккаунты, которые у вас уже есть
{"cart":{"kind":"extend","gb":50,"months":1,"users":3,"extend_vpn_ids":["vpn_6t2k9p","vpn_1a4b7c"]}}
Купить карточку с фиксированной ценой вместо собранной корзины
{"cart":{"kind":"new","bundle_id":"card_100_1m","new_accounts":1}}
Ответ200 · application/json
quoteobject

Цена по позициям. Ничего не создаётся и ничего не списывается.

quote.model_namestring

Какая модель ценообразования ответила.

quote.model_typestring

Версия движка модели.

quote.base_usdmoney

Цена до скидок и надбавок.

quote.total_usdmoney

Итоговая цена — сумма, которую спишет продажа с этой корзиной.

quote.linesarray

Постатейная разбивка, со знаками, в точности суммирующаяся в итог.

quote.lines[].codestring

Что это за строка (base, код скидки, надбавка…).

quote.lines[].kindstring

Категория строки, для группировки в вашем интерфейсе.

quote.lines[].amount_usdmoney

Со знаком. Скидки отрицательные; строки в точности суммируются в total_usd.

quote.lines[].pctstring

Процент за строкой, когда он есть.

quote.cappedbool

Итог упёрся в потолок модели.

quote.floor_appliedbool

Итог был поднят до нижней границы модели.

quote.clampedenum

Установлено, если значение корзины было приведено к границам перед расчётом цены.

Одно из:minmax
quote.invalidstring

Непустое значение означает, что корзину нельзя оценить — покажите его и НИКОГДА не списывайте деньги по такому расчёту.

quote.metamap

Дополнительные данные модели, строка→строка (например, remaining_days у апгрейда).

Пример ответа
{
  "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"}
    ]
  }
}

Продажа VPN

POST

CreateVPNOrder

buyIdempotency-Key
https://apiservice.vitamindata.net/api/v1/CreateVPNOrder

Покупает новые VPN-аккаунты или продлевает существующие ("kind":"extend" с extend_vpn_ids).

О двух формах ответа см. Оплата.

Запрос
cartobjectобязательное

Что купить — та же структура, которую оценивает Quote.

cart.kindenumобязательное

Купить новые аккаунты или добавить трафик и время существующим.

Одно из:newextend
cart.gbintнеобязательно

Трафик на аккаунт, в ГБ, в границах из ListPlans.

cart.monthsintнеобязательно

Срок действия на аккаунт, в месяцах.

cart.usersintнеобязательно

Одновременных устройств на аккаунт.

cart.new_accountsintнеобязательно

Только для kind:"new": сколько аккаунтов создать. Имена пользователей генерирует сервер.

cart.extend_vpn_idsarrayнеобязательно

Только для kind:"extend": какие аккаунты продлить, по публичным идентификаторам.

cart.bundle_idstringнеобязательно

Покупает карточку с фиксированной ценой из ListPlans.bundles вместо настраиваемой корзины. Если задано, гб/месяцы/пользователи игнорируются — действуют значения и цена самой карточки.

fundingenumобязательное

Как платить — см. Оплата. Значения по умолчанию нет: запрос без него отклоняется.

Одно из:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyнеобязательно

Страховка подтверждения. Если задано и наш свежий расчёт отличается, продажа отклоняется с price_changed, вместо того чтобы списать сумму, которой ваш клиент не видел.

Пример запроса
curl 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"}'
Другие формы этого запроса
Продлить аккаунты, которые у вас уже есть
{"cart":{"kind":"extend","gb":50,"months":1,"users":3,"extend_vpn_ids":["vpn_6t2k9p"]},"funding":"FUNDING_AUTO"}
Купить карточку с фиксированной ценой, оплата с баланса
{"cart":{"kind":"new","bundle_id":"card_100_1m","new_accounts":1},"funding":"FUNDING_BALANCE"}
Ответ200 · application/json
orderobject

Заказ — опрашивайте GetOrder, пока статус не станет delivered.

order.order_idstring

Публичный идентификатор заказа (ord_…).

order.productenum

Что было куплено.

Одно из:vpnvps
order.kindstring

Форма покупки: new, extend, upgrade

order.statusenum

Жизненный цикл. Цель — delivered; needs_operator означает, что деньги пришли и выдачу завершает человек — не покупайте повторно; expired означает, что счёт истёк неоплаченным.

Одно из:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum

Каким способом заказ был фактически оплачен. FUNDING_AUTO разрешается в один из них.

Одно из:invoicebalance
order.total_usdmoney

Сумма, которую списывает заказ.

order.invoice_idstring

Счёт за заказом — он есть у каждого заказа, каким бы способом тот ни был оплачен.

order.itemsint

Сколько услуг заказ создаёт или продлевает.

order.created_atunix

Когда заказ был размещён.

order.delivered_atunix

Когда завершилась выдача. До этого отсутствует.

order.breakdownobject

Расчёт, на который согласился клиент, дословно — та же структура, что возвращает Quote.

invoiceobject

Счёт за заказом: подлежит оплате при payment_required, уже оплачен при completed.

invoice.invoice_idstring

Идентификатор счёта в шлюзе (inv_…).

invoice.statusenum

pending — можно оплачивать. Всё от confirmed до delivered_redirected означает, что деньги пришли необратимо — считайте все эти статусы ОПЛАЧЕННЫМИ. expired означает, что ссылка истекла неоплаченной.

Одно из:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

Размещённая у нас страница оплаты. Отправляйте клиента сюда; за ней живут все способы оплаты (монеты, сети, баланс).

invoice.pay_telegram_urlstring

Тот же счёт, оплачиваемый прямо в Telegram: ссылка открывает бот самого платёжного провайдера, который показывает сумму и там же принимает оплату. Предлагайте её рядом с pay_url тем, кто предпочитает не выходить из приложения. Может отсутствовать — она есть только у платёжного провайдера с настроенным ботом, поэтому никогда не делайте её единственной кнопкой оплаты.

invoice.price_usdmoney

Сумма, которую собирает счёт.

invoice.expires_atunix

Когда закрывается окно оплаты.

paidbool

Деньги получены. Отсутствует (= false) при payment_required.

statusenum

ГЛАВНОЕ поле для ветвления — см. Оплата.

Одно из:completedpayment_required
Пример ответа
{
  "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"
}
POST

GetOrder

read
https://apiservice.vitamindata.net/api/v1/GetOrder

Опрашивайте это после покупки: created → invoiced → paid → delivering → delivered.

Запрос
order_idstringобязательное

Из размещённого вами заказа.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetOrder \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"order_id":"ord_7b2c9d"}'
Ответ200 · application/json
orderobject

Заказ, с полной разбивкой.

order.order_idstring

Публичный идентификатор заказа (ord_…).

order.productenum

Что было куплено.

Одно из:vpnvps
order.kindstring

Форма покупки: new, extend, upgrade

order.statusenum

Жизненный цикл. Цель — delivered; needs_operator означает, что деньги пришли и выдачу завершает человек — не покупайте повторно; expired означает, что счёт истёк неоплаченным.

Одно из:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum

Каким способом заказ был фактически оплачен. FUNDING_AUTO разрешается в один из них.

Одно из:invoicebalance
order.total_usdmoney

Сумма, которую списывает заказ.

order.invoice_idstring

Счёт за заказом — он есть у каждого заказа, каким бы способом тот ни был оплачен.

order.itemsint

Сколько услуг заказ создаёт или продлевает.

order.created_atunix

Когда заказ был размещён.

order.delivered_atunix

Когда завершилась выдача. До этого отсутствует.

order.breakdownobject

Расчёт, на который согласился клиент, дословно — та же структура, что возвращает Quote.

invoiceobject

Присутствует, только пока заказ ждёт оплаты, — та же структура, что и везде.

Пример ответа
{
  "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"}
    ]
  }
  }
}
POST

ListOrders

read
https://apiservice.vitamindata.net/api/v1/ListOrders

История ваших заказов, сначала новые.

Запрос
limitintнеобязательно

Размер страницы. По умолчанию 25, максимум 100.

cursorcursorнеобязательно

next_cursor из предыдущего ответа. Для первой страницы опустите.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/ListOrders \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"limit":25,"cursor":""}'
Ответ200 · application/json
ordersarray

Заказы.

orders[].order_idstring

Публичный идентификатор заказа (ord_…).

orders[].productenum

Что было куплено.

Одно из:vpnvps
orders[].kindstring

Форма покупки: new, extend, upgrade

orders[].statusenum

Жизненный цикл. Цель — delivered; needs_operator означает, что деньги пришли и выдачу завершает человек — не покупайте повторно; expired означает, что счёт истёк неоплаченным.

Одно из:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
orders[].fundingenum

Каким способом заказ был фактически оплачен. FUNDING_AUTO разрешается в один из них.

Одно из:invoicebalance
orders[].total_usdmoney

Сумма, которую списывает заказ.

orders[].invoice_idstring

Счёт за заказом — он есть у каждого заказа, каким бы способом тот ни был оплачен.

orders[].itemsint

Сколько услуг заказ создаёт или продлевает.

orders[].created_atunix

Когда заказ был размещён.

orders[].delivered_atunix

Когда завершилась выдача. До этого отсутствует.

orders[].breakdownobject

Расчёт, на который согласился клиент, дословно — та же структура, что возвращает Quote.

next_cursorcursor

Верните его как cursor, чтобы получить следующую страницу. Отсутствует/пустой = вы получили всё.

Пример ответа
{
  "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"}
  ]
}

Управление VPN

POST

ListVPN

read
https://apiservice.vitamindata.net/api/v1/ListVPN

Все ваши VPN-аккаунты, с остатком трафика и датой окончания.

Запрос
limitintнеобязательно

Размер страницы. По умолчанию 50, максимум 200.

cursorcursorнеобязательно

next_cursor из предыдущего ответа. Для первой страницы опустите.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/ListVPN \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"limit":25,"cursor":""}'
Ответ200 · application/json
vpnsarray

Ваши аккаунты.

vpns[].vpn_idstring

Публичный идентификатор, который принимают все остальные VPN-методы.

vpns[].usernamestring

Логин, который показывают приложения.

vpns[].statusstring

Состояние аккаунта, как его показывает панель — active, если он не приостановлен и не истёк.

vpns[].remaining_bytesbytes

Трафик, оставшийся суммарно по всем его пакетам.

vpns[].total_downloadbytes

Скачано за всё время, по данным живого VPN-плана. В ListVPN всегда 0 — список отдаётся из кэша, в котором нет разбивки по направлениям. Для списка используйте used_bytes, для разбивки — GetVPN/GetVPNUsage.

vpns[].total_uploadbytes

Отдано за всё время. То же замечание, что и для total_download: в ListVPN это 0.

vpns[].used_bytesbytes

Фактически израсходованный трафик за всё время (приём + отдача). Эта величина поддерживается для каждого VPN, поэтому верна на всех эндпоинтах, включая ListVPN.

vpns[].expires_atunix

Когда аккаунт истекает.

vpns[].max_onlineint

Допустимое число одновременных устройств.

vpns[].daily_limit_bytesbytes

Сегодняшний предел. Отсутствует/0 = дневного предела НЕТ.

vpns[].daily_used_bytesbytes

Израсходовано из сегодняшнего предела.

vpns[].daily_reset_unixunix

Когда сбрасывается дневной счётчик.

vpns[].allowed_protocolsint

Битовая маска протоколов для наших приложений. Считайте её непрозрачной.

vpns[].cache_atunix

Насколько свежи цифры: они не новее этой метки времени, если не установлен live.

vpns[].created_atunix

Когда аккаунт был создан.

vpns[].livebool

Цифры только что получены из сети, а не из кэша.

next_cursorcursor

Верните его как cursor, чтобы получить следующую страницу. Отсутствует/пустой = вы получили всё.

Пример ответа
{
  "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"
}
POST

GetVPN

read
https://apiservice.vitamindata.net/api/v1/GetVPN

Один аккаунт подробно. live:true означает, что цифры только что получены из сети.

Запрос
vpn_idstringобязательное

Публичный идентификатор аккаунта (vpn_…), из ListVPN или из выдачи заказа.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetVPN \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"vpn_id":"vpn_6t2k9p"}'
Ответ200 · application/json
vpnobject

Аккаунт.

vpn.vpn_idstring

Публичный идентификатор, который принимают все остальные VPN-методы.

vpn.usernamestring

Логин, который показывают приложения.

vpn.statusstring

Состояние аккаунта, как его показывает панель — active, если он не приостановлен и не истёк.

vpn.remaining_bytesbytes

Трафик, оставшийся суммарно по всем его пакетам.

vpn.total_downloadbytes

Скачано за всё время, по данным живого VPN-плана. В ListVPN всегда 0 — список отдаётся из кэша, в котором нет разбивки по направлениям. Для списка используйте used_bytes, для разбивки — GetVPN/GetVPNUsage.

vpn.total_uploadbytes

Отдано за всё время. То же замечание, что и для total_download: в ListVPN это 0.

vpn.used_bytesbytes

Фактически израсходованный трафик за всё время (приём + отдача). Эта величина поддерживается для каждого VPN, поэтому верна на всех эндпоинтах, включая ListVPN.

vpn.expires_atunix

Когда аккаунт истекает.

vpn.max_onlineint

Допустимое число одновременных устройств.

vpn.daily_limit_bytesbytes

Сегодняшний предел. Отсутствует/0 = дневного предела НЕТ.

vpn.daily_used_bytesbytes

Израсходовано из сегодняшнего предела.

vpn.daily_reset_unixunix

Когда сбрасывается дневной счётчик.

vpn.allowed_protocolsint

Битовая маска протоколов для наших приложений. Считайте её непрозрачной.

vpn.cache_atunix

Насколько свежи цифры: они не новее этой метки времени, если не установлен live.

vpn.created_atunix

Когда аккаунт был создан.

vpn.livebool

Цифры только что получены из сети, а не из кэша.

livebool

Свежие данные из сети. Отсутствует = ответ отдан из модели чтения и его возраст — cache_at.

Пример ответа
{
  "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
}
POST

GetVPNUsage

read
https://apiservice.vitamindata.net/api/v1/GetVPNUsage

Израсходованный и оставшийся трафик, плюс сегодняшний предел, если он есть.

Запрос
vpn_idstringобязательное

Публичный идентификатор аккаунта (vpn_…), из ListVPN или из выдачи заказа.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetVPNUsage \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"vpn_id":"vpn_6t2k9p"}'
Ответ200 · application/json
vpn_idstring

Возвращается эхом.

remaining_bytesbytes

Оставшийся трафик.

total_downloadbytes

Скачано за всё время.

total_uploadbytes

Отдано за всё время.

expires_atunix

Когда аккаунт истекает.

daily_limit_bytesbytes

Сегодняшний предел. Отсутствует = предела нет.

daily_used_bytesbytes

Израсходовано из сегодняшнего предела.

daily_reset_unixunix

Когда сбрасывается дневной счётчик.

cache_atunix

Свежесть цифр, когда они не получены вживую.

livebool

Только что получено из сети.

seriesarray

Зарезервировано под исторический ряд потребления — сегодня пусто.

series[].tunix

Начало интервала.

series[].rxbytes

Скачано за интервал.

series[].txbytes

Отдано за интервал.

Пример ответа
{
  "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
}
POST

ListVPNBundles

read
https://apiservice.vitamindata.net/api/v1/ListVPNBundles

Кошельки трафика за одним аккаунтом, в порядке их расходования.

Именно так вы отвечаете на вопрос «почему у клиента убавился платный трафик, пока оставался бесплатный?» — следующим расходуется queue_position 1. live:false означает, что мы не смогли их прочитать, а не что их нет.

Запрос
vpn_idstringобязательное

Публичный идентификатор аккаунта (vpn_…), из ListVPN или из выдачи заказа.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/ListVPNBundles \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"vpn_id":"vpn_6t2k9p"}'
Ответ200 · application/json
bundlesarray

Кошельки, в порядке расходования.

bundles[].bundle_idstring

Идентификатор кошелька.

bundles[].freebool

Выдан в рамках бесплатного уровня, а не куплен.

bundles[].sourceenum

Откуда взялся кошелёк.

Одно из:buyextendmigratedfree_tier
bundles[].granted_bytesbytes

Его полный размер на момент выдачи.

bundles[].remaining_bytesbytes

Сколько в нём осталось.

bundles[].granted_atunix

Когда он был выдан.

bundles[].expires_atunix

Когда он истекает — независимо от того, израсходован или нет.

bundles[].daily_limit_bytesbytes

Его собственный дневной предел. Отсутствует = предела нет.

bundles[].statusenum

Словами, а не числами, — чтобы вам не пришлось запоминать, что 2 значит «исчерпан».

Одно из:activedisabledexhausted
bundles[].queue_positionint

Нумерация с 1 по ПРИГОДНЫМ кошелькам, в порядке расходования — следующим расходуется 1. 0/отсутствует означает, что кошелёк вне очереди (израсходован, истёк или отключён).

bundles[].plan_gbint

Размер, с которым он продавался, в ГБ.

bundles[].plan_daysint

Срок действия, с которым он продавался, в днях.

bundles[].invoice_idstring

Покупка, из которой он появился. Отсутствует у бесплатной выдачи.

livebool

Отсутствует/false = система учёта прав была недоступна, поэтому список ПУСТОЙ, а не неверный. «Мы не смогли их прочитать» и «их нет» — разные утверждения.

Пример ответа
{
  "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

SetVPNPassword

credentials
https://apiservice.vitamindata.net/api/v1/SetVPNPassword

Меняет пароль аккаунта.

Требует отдельную область credentialsmanage её никогда не подразумевает.

Запрос
vpn_idstringобязательное

Публичный идентификатор аккаунта (vpn_…), из ListVPN или из выдачи заказа.

new_passwordstringобязательное

Пароль, который нужно установить.

credentialstringнеобязательно

Какой логин — для аккаунтов с несколькими. Пусто = основной.

Пример запроса
curl 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":""}'
Ответ200 · application/json
usernamestring

Логин, к которому применилось изменение.

Пример ответа
{"username": "u482913"}
POST

SetVPNState

manage
https://apiservice.vitamindata.net/api/v1/SetVPNState

Приостанавливает или возобновляет аккаунт.

Запрос
vpn_idstringобязательное

Публичный идентификатор аккаунта (vpn_…), из ListVPN или из выдачи заказа.

stateenumобязательное

Что сделать.

Одно из:suspendresume
Пример запроса
curl 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"}'
Ответ200 · application/json
statusenum

Состояние, в котором оказался аккаунт.

Одно из:suspendedactive
Пример ответа
{"status": "suspended"}
POST

DeleteVPN

manage
https://apiservice.vitamindata.net/api/v1/DeleteVPN

Удаляет аккаунт. Отмены и возврата нет.

Запрос
vpn_idstringобязательное

Публичный идентификатор аккаунта (vpn_…), из ListVPN или из выдачи заказа.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/DeleteVPN \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"vpn_id":"vpn_6t2k9p"}'
Ответ200 · application/json
statusenum

При успехе всегда deleted.

Одно из:deleted
Пример ответа
{"status": "deleted"}

Продажа серверов

Продажа VPS — тот же контракт оплаты, что и продажа VPN, отличается только корзина.

POST

GetVPSStorefront

read
https://apiservice.vitamindata.net/api/v1/GetVPSStorefront

Локации, тарифы с ценами в каждой из них и загрузочные образы.

Узел с available:false исчерпал ёмкость — показывайте его, но не предлагайте к покупке.

Запрос

Параметров нет — отправьте пустой объект, {}.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetVPSStorefront \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
Ответ200 · application/json
nodesarray

Локации, каждая со своими тарифами и ценами.

nodes[].node_idstring

То, что принимает node_id корзины.

nodes[].labelstring

Отображаемое имя (Frankfurt).

nodes[].regionstring

Грубый код региона для группировки.

nodes[].countrystring

Код страны ISO, для флагов.

nodes[].availablebool

Отсутствует/false = ёмкость исчерпана: показывайте, но не предлагайте к покупке.

nodes[].plansarray

Что здесь продаётся, с ценами.

nodes[].plans[].plan_codestring

То, что принимает plan_code корзины.

nodes[].plans[].namestring

Отображаемое имя.

nodes[].plans[].vcpuint

Ядра.

nodes[].plans[].ram_mbint

Память в МБ.

nodes[].plans[].disk_gbint

Диск в ГБ.

nodes[].plans[].traffic_bytesbytes

Включённый месячный трафик.

nodes[].plans[].price_usd_monthmoney

Месячная цена НА ЭТОМ УЗЛЕ — тот же тариф в другом месте может стоить иначе.

imagesarray

Всё, что можно загрузить или установить.

images[].shastring

ЕДИНСТВЕННЫЙ идентификатор образа — его принимают корзина, переустановка и подключение ISO.

images[].namestring

Человекочитаемое имя (Debian 13).

images[].kindenum

Образ disk разворачивается напрямую; iso — установщик, с которого вы загружаетесь.

Одно из:diskiso
images[].os_familyenum

Для группировки и иконок в вашем интерфейсе.

Одно из:linuxwindowsmikrotik
images[].min_disk_gbint

Переустановка на диск меньшего размера отклоняется — сначала увеличьте диск.

months_minint

Минимальный срок, на который можно купить новую VM.

months_maxint

Максимальный.

Пример ответа
{
  "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
}
POST

ListVPSImages

read
https://apiservice.vitamindata.net/api/v1/ListVPSImages

Все образы, которые можно загрузить или установить, по sha.

Именно этот sha принимают корзина, переустановка и подключение ISO. Больше образ ничем не задаётся.

Запрос

Параметров нет — отправьте пустой объект, {}.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/ListVPSImages \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
Ответ200 · application/json
imagesarray

Каталог.

images[].shastring

ЕДИНСТВЕННЫЙ идентификатор образа — его принимают корзина, переустановка и подключение ISO.

images[].namestring

Человекочитаемое имя (Debian 13).

images[].kindenum

Образ disk разворачивается напрямую; iso — установщик, с которого вы загружаетесь.

Одно из:diskiso
images[].os_familyenum

Для группировки и иконок в вашем интерфейсе.

Одно из:linuxwindowsmikrotik
images[].min_disk_gbint

Переустановка на диск меньшего размера отклоняется — сначала увеличьте диск.

Пример ответа
{
  "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}
  ]
}
POST

QuoteVPS

read
https://apiservice.vitamindata.net/api/v1/QuoteVPS

Цена нового сервера, по позициям.

Запрос
cartobjectобязательное

Сервер для расчёта цены.

cart.node_idstringобязательное

Где создать VM, из узлов магазина.

cart.placementstringзарезервировано — не отправляйте

Зарезервировано. В этом API место создания сервера всегда определяет node_id — передавайте его, а узел выбирайте сами из магазина.

Одно из:auto
cart.plan_codestringобязательное

Тариф, из собственного прайс-листа выбранного узла — тарифы и цены различаются между узлами.

cart.image_shastringобязательное

Что загрузить или установить, по sha. Дисковые образы разворачиваются напрямую; установочный ISO приходит уже подключённым, и VM настроена загружаться с него.

cart.namestringобязательное

Имя хоста / метка VM.

cart.monthsintобязательное

Начальный срок, в границах месяцев магазина.

cart.extra_disk_gbintнеобязательно

Дополнительный диск сверх тарифа, в ГБ.

cart.extra_ipsintнеобязательно

Дополнительные публичные IPv4-адреса.

cart.extra_traffic_tbmoneyнеобязательно

Дополнительный месячный трафик в ТБ, десятичной строкой ("0.5").

Пример запроса
curl 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"}}'
Ответ200 · application/json
quoteobject

Цена по позициям. Ничего не создаётся и ничего не списывается.

quote.model_namestring

Какая модель ценообразования ответила.

quote.model_typestring

Версия движка модели.

quote.base_usdmoney

Цена до скидок и надбавок.

quote.total_usdmoney

Итоговая цена — сумма, которую спишет продажа с этой корзиной.

quote.linesarray

Постатейная разбивка, со знаками, в точности суммирующаяся в итог.

quote.lines[].codestring

Что это за строка (base, код скидки, надбавка…).

quote.lines[].kindstring

Категория строки, для группировки в вашем интерфейсе.

quote.lines[].amount_usdmoney

Со знаком. Скидки отрицательные; строки в точности суммируются в total_usd.

quote.lines[].pctstring

Процент за строкой, когда он есть.

quote.cappedbool

Итог упёрся в потолок модели.

quote.floor_appliedbool

Итог был поднят до нижней границы модели.

quote.clampedenum

Установлено, если значение корзины было приведено к границам перед расчётом цены.

Одно из:minmax
quote.invalidstring

Непустое значение означает, что корзину нельзя оценить — покажите его и НИКОГДА не списывайте деньги по такому расчёту.

quote.metamap

Дополнительные данные модели, строка→строка (например, remaining_days у апгрейда).

Пример ответа
{
  "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/CreateVPSOrder

Покупает и разворачивает сервер.

Опрашивайте GetOrder о выдаче, затем GetVPS о самой машине.

Запрос
cartobjectобязательное

Что создать — та же структура, которую оценивает QuoteVPS.

cart.node_idstringобязательное

Где создать VM, из узлов магазина.

cart.placementstringзарезервировано — не отправляйте

Зарезервировано. В этом API место создания сервера всегда определяет node_id — передавайте его, а узел выбирайте сами из магазина.

Одно из:auto
cart.plan_codestringобязательное

Тариф, из собственного прайс-листа выбранного узла — тарифы и цены различаются между узлами.

cart.image_shastringобязательное

Что загрузить или установить, по sha. Дисковые образы разворачиваются напрямую; установочный ISO приходит уже подключённым, и VM настроена загружаться с него.

cart.namestringобязательное

Имя хоста / метка VM.

cart.monthsintобязательное

Начальный срок, в границах месяцев магазина.

cart.extra_disk_gbintнеобязательно

Дополнительный диск сверх тарифа, в ГБ.

cart.extra_ipsintнеобязательно

Дополнительные публичные IPv4-адреса.

cart.extra_traffic_tbmoneyнеобязательно

Дополнительный месячный трафик в ТБ, десятичной строкой ("0.5").

fundingenumобязательное

Как платить — см. Оплата. Значения по умолчанию нет: запрос без него отклоняется.

Одно из:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyнеобязательно

Страховка подтверждения. Если задано и наш свежий расчёт отличается, продажа отклоняется с price_changed, вместо того чтобы списать сумму, которой ваш клиент не видел.

Пример запроса
curl 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"}'
Ответ200 · application/json
orderobject

Заказ — опрашивайте GetOrder, пока статус не станет delivered.

order.order_idstring

Публичный идентификатор заказа (ord_…).

order.productenum

Что было куплено.

Одно из:vpnvps
order.kindstring

Форма покупки: new, extend, upgrade

order.statusenum

Жизненный цикл. Цель — delivered; needs_operator означает, что деньги пришли и выдачу завершает человек — не покупайте повторно; expired означает, что счёт истёк неоплаченным.

Одно из:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum

Каким способом заказ был фактически оплачен. FUNDING_AUTO разрешается в один из них.

Одно из:invoicebalance
order.total_usdmoney

Сумма, которую списывает заказ.

order.invoice_idstring

Счёт за заказом — он есть у каждого заказа, каким бы способом тот ни был оплачен.

order.itemsint

Сколько услуг заказ создаёт или продлевает.

order.created_atunix

Когда заказ был размещён.

order.delivered_atunix

Когда завершилась выдача. До этого отсутствует.

order.breakdownobject

Расчёт, на который согласился клиент, дословно — та же структура, что возвращает Quote.

invoiceobject

Счёт за заказом: подлежит оплате при payment_required, уже оплачен при completed.

invoice.invoice_idstring

Идентификатор счёта в шлюзе (inv_…).

invoice.statusenum

pending — можно оплачивать. Всё от confirmed до delivered_redirected означает, что деньги пришли необратимо — считайте все эти статусы ОПЛАЧЕННЫМИ. expired означает, что ссылка истекла неоплаченной.

Одно из:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

Размещённая у нас страница оплаты. Отправляйте клиента сюда; за ней живут все способы оплаты (монеты, сети, баланс).

invoice.pay_telegram_urlstring

Тот же счёт, оплачиваемый прямо в Telegram: ссылка открывает бот самого платёжного провайдера, который показывает сумму и там же принимает оплату. Предлагайте её рядом с pay_url тем, кто предпочитает не выходить из приложения. Может отсутствовать — она есть только у платёжного провайдера с настроенным ботом, поэтому никогда не делайте её единственной кнопкой оплаты.

invoice.price_usdmoney

Сумма, которую собирает счёт.

invoice.expires_atunix

Когда закрывается окно оплаты.

paidbool

Деньги получены. Отсутствует (= false) при payment_required.

statusenum

ГЛАВНОЕ поле для ветвления — см. Оплата.

Одно из:completedpayment_required
Пример ответа
{
  "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"
}
POST

QuoteVPSExtend

read
https://apiservice.vitamindata.net/api/v1/QuoteVPSExtend

Сколько стоит продление сервера.

Запрос
vps_idstringобязательное

Идентификатор сервера, из ListVPS.

monthsintобязательное

Сколько месяцев добавить. months_minmonths_max магазина — это то, что стоит предлагать в вашем интерфейсе, но продление к ним НЕ приводится: передавайте разумное число, потому что рассчитано и списано будет ровно то, что вы передали.

Пример запроса
curl 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}'
Ответ200 · application/json
quoteobject

Цена по позициям. Ничего не создаётся и ничего не списывается.

quote.model_namestring

Какая модель ценообразования ответила.

quote.model_typestring

Версия движка модели.

quote.base_usdmoney

Цена до скидок и надбавок.

quote.total_usdmoney

Итоговая цена — сумма, которую спишет продажа с этой корзиной.

quote.linesarray

Постатейная разбивка, со знаками, в точности суммирующаяся в итог.

quote.lines[].codestring

Что это за строка (base, код скидки, надбавка…).

quote.lines[].kindstring

Категория строки, для группировки в вашем интерфейсе.

quote.lines[].amount_usdmoney

Со знаком. Скидки отрицательные; строки в точности суммируются в total_usd.

quote.lines[].pctstring

Процент за строкой, когда он есть.

quote.cappedbool

Итог упёрся в потолок модели.

quote.floor_appliedbool

Итог был поднят до нижней границы модели.

quote.clampedenum

Установлено, если значение корзины было приведено к границам перед расчётом цены.

Одно из:minmax
quote.invalidstring

Непустое значение означает, что корзину нельзя оценить — покажите его и НИКОГДА не списывайте деньги по такому расчёту.

quote.metamap

Дополнительные данные модели, строка→строка (например, remaining_days у апгрейда).

Пример ответа
{
  "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/ExtendVPS

Продлевает сервер.

Продлевать заранее не дороже: новая дата окончания считается от текущей, а не от сегодняшнего дня.

Запрос
vps_idstringобязательное

Идентификатор сервера, из ListVPS.

monthsintобязательное

Сколько месяцев добавить. months_minmonths_max магазина — это то, что стоит предлагать в вашем интерфейсе, но продление к ним НЕ приводится: передавайте разумное число, потому что рассчитано и списано будет ровно то, что вы передали.

fundingenumобязательное

Как платить — см. Оплата. Значения по умолчанию нет: запрос без него отклоняется.

Одно из:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyнеобязательно

Страховка подтверждения. Если задано и наш свежий расчёт отличается, продажа отклоняется с price_changed, вместо того чтобы списать сумму, которой ваш клиент не видел.

Пример запроса
curl 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"}'
Ответ200 · application/json
orderobject

Заказ — опрашивайте GetOrder, пока статус не станет delivered.

order.order_idstring

Публичный идентификатор заказа (ord_…).

order.productenum

Что было куплено.

Одно из:vpnvps
order.kindstring

Форма покупки: new, extend, upgrade

order.statusenum

Жизненный цикл. Цель — delivered; needs_operator означает, что деньги пришли и выдачу завершает человек — не покупайте повторно; expired означает, что счёт истёк неоплаченным.

Одно из:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum

Каким способом заказ был фактически оплачен. FUNDING_AUTO разрешается в один из них.

Одно из:invoicebalance
order.total_usdmoney

Сумма, которую списывает заказ.

order.invoice_idstring

Счёт за заказом — он есть у каждого заказа, каким бы способом тот ни был оплачен.

order.itemsint

Сколько услуг заказ создаёт или продлевает.

order.created_atunix

Когда заказ был размещён.

order.delivered_atunix

Когда завершилась выдача. До этого отсутствует.

order.breakdownobject

Расчёт, на который согласился клиент, дословно — та же структура, что возвращает Quote.

invoiceobject

Счёт за заказом: подлежит оплате при payment_required, уже оплачен при completed.

invoice.invoice_idstring

Идентификатор счёта в шлюзе (inv_…).

invoice.statusenum

pending — можно оплачивать. Всё от confirmed до delivered_redirected означает, что деньги пришли необратимо — считайте все эти статусы ОПЛАЧЕННЫМИ. expired означает, что ссылка истекла неоплаченной.

Одно из:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

Размещённая у нас страница оплаты. Отправляйте клиента сюда; за ней живут все способы оплаты (монеты, сети, баланс).

invoice.pay_telegram_urlstring

Тот же счёт, оплачиваемый прямо в Telegram: ссылка открывает бот самого платёжного провайдера, который показывает сумму и там же принимает оплату. Предлагайте её рядом с pay_url тем, кто предпочитает не выходить из приложения. Может отсутствовать — она есть только у платёжного провайдера с настроенным ботом, поэтому никогда не делайте её единственной кнопкой оплаты.

invoice.price_usdmoney

Сумма, которую собирает счёт.

invoice.expires_atunix

Когда закрывается окно оплаты.

paidbool

Деньги получены. Отсутствует (= false) при payment_required.

statusenum

ГЛАВНОЕ поле для ветвления — см. Оплата.

Одно из:completedpayment_required
Пример ответа
{
  "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"
}
POST

QuoteVPSUpgrade

read
https://apiservice.vitamindata.net/api/v1/QuoteVPSUpgrade

Сколько стоит конфигурация побольше, пропорционально уже оплаченному времени.

Запрос
vps_idstringобязательное

Идентификатор сервера, из ListVPS.

specobjectобязательное

ЦЕЛЕВАЯ конфигурация. Опущенные/нулевые поля сохраняют текущее значение.

spec.vcpuintнеобязательно

Целевое число ядер. 0 сохраняет текущее значение.

spec.ram_mbintнеобязательно

Целевая память в МБ. 0 сохраняет текущее значение.

spec.disk_gbintнеобязательно

Целевой диск в ГБ. Диск только растёт — меньшее значение отклоняется: уменьшение файловой системы под работающей ОС — это потеря данных.

Пример запроса
curl 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}}'
Ответ200 · application/json
quoteobject

Цена по позициям. Ничего не создаётся и ничего не списывается.

quote.model_namestring

Какая модель ценообразования ответила.

quote.model_typestring

Версия движка модели.

quote.base_usdmoney

Цена до скидок и надбавок.

quote.total_usdmoney

Итоговая цена — сумма, которую спишет продажа с этой корзиной.

quote.linesarray

Постатейная разбивка, со знаками, в точности суммирующаяся в итог.

quote.lines[].codestring

Что это за строка (base, код скидки, надбавка…).

quote.lines[].kindstring

Категория строки, для группировки в вашем интерфейсе.

quote.lines[].amount_usdmoney

Со знаком. Скидки отрицательные; строки в точности суммируются в total_usd.

quote.lines[].pctstring

Процент за строкой, когда он есть.

quote.cappedbool

Итог упёрся в потолок модели.

quote.floor_appliedbool

Итог был поднят до нижней границы модели.

quote.clampedenum

Установлено, если значение корзины было приведено к границам перед расчётом цены.

Одно из:minmax
quote.invalidstring

Непустое значение означает, что корзину нельзя оценить — покажите его и НИКОГДА не списывайте деньги по такому расчёту.

quote.metamap

Дополнительные данные модели, строка→строка (например, remaining_days у апгрейда).

restart_requiredbool

Применение этой конфигурации требует перезапуска питания — клиент должен узнать об этом ДО оплаты.

monthly_before_usdmoney

Регулярная цена сегодня.

monthly_after_usdmoney

Регулярная цена после апгрейда — сколько отныне будут стоить продления.

Пример ответа
{
  "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/UpgradeVPS

Оплачивает и применяет конфигурацию побольше. Диск может только расти.

Запрос
vps_idstringобязательное

Идентификатор сервера, из ListVPS.

specobjectобязательное

ЦЕЛЕВАЯ конфигурация — сначала рассчитайте её цену; расчёт заодно скажет о перезагрузке.

spec.vcpuintнеобязательно

Целевое число ядер. 0 сохраняет текущее значение.

spec.ram_mbintнеобязательно

Целевая память в МБ. 0 сохраняет текущее значение.

spec.disk_gbintнеобязательно

Целевой диск в ГБ. Диск только растёт — меньшее значение отклоняется: уменьшение файловой системы под работающей ОС — это потеря данных.

fundingenumобязательное

Как платить — см. Оплата. Значения по умолчанию нет: запрос без него отклоняется.

Одно из:FUNDING_AUTOFUNDING_BALANCEFUNDING_INVOICE
expected_total_usdmoneyнеобязательно

Страховка подтверждения. Если задано и наш свежий расчёт отличается, продажа отклоняется с price_changed, вместо того чтобы списать сумму, которой ваш клиент не видел.

Пример запроса
curl 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"}'
Ответ200 · application/json
orderobject

Заказ — опрашивайте GetOrder, пока статус не станет delivered.

order.order_idstring

Публичный идентификатор заказа (ord_…).

order.productenum

Что было куплено.

Одно из:vpnvps
order.kindstring

Форма покупки: new, extend, upgrade

order.statusenum

Жизненный цикл. Цель — delivered; needs_operator означает, что деньги пришли и выдачу завершает человек — не покупайте повторно; expired означает, что счёт истёк неоплаченным.

Одно из:createdinvoicedpaiddeliveringdeliveredneeds_operatorfailedrefund_pendingrefundedexpired
order.fundingenum

Каким способом заказ был фактически оплачен. FUNDING_AUTO разрешается в один из них.

Одно из:invoicebalance
order.total_usdmoney

Сумма, которую списывает заказ.

order.invoice_idstring

Счёт за заказом — он есть у каждого заказа, каким бы способом тот ни был оплачен.

order.itemsint

Сколько услуг заказ создаёт или продлевает.

order.created_atunix

Когда заказ был размещён.

order.delivered_atunix

Когда завершилась выдача. До этого отсутствует.

order.breakdownobject

Расчёт, на который согласился клиент, дословно — та же структура, что возвращает Quote.

invoiceobject

Счёт за заказом: подлежит оплате при payment_required, уже оплачен при completed.

invoice.invoice_idstring

Идентификатор счёта в шлюзе (inv_…).

invoice.statusenum

pending — можно оплачивать. Всё от confirmed до delivered_redirected означает, что деньги пришли необратимо — считайте все эти статусы ОПЛАЧЕННЫМИ. expired означает, что ссылка истекла неоплаченной.

Одно из:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

Размещённая у нас страница оплаты. Отправляйте клиента сюда; за ней живут все способы оплаты (монеты, сети, баланс).

invoice.pay_telegram_urlstring

Тот же счёт, оплачиваемый прямо в Telegram: ссылка открывает бот самого платёжного провайдера, который показывает сумму и там же принимает оплату. Предлагайте её рядом с pay_url тем, кто предпочитает не выходить из приложения. Может отсутствовать — она есть только у платёжного провайдера с настроенным ботом, поэтому никогда не делайте её единственной кнопкой оплаты.

invoice.price_usdmoney

Сумма, которую собирает счёт.

invoice.expires_atunix

Когда закрывается окно оплаты.

paidbool

Деньги получены. Отсутствует (= false) при payment_required.

statusenum

ГЛАВНОЕ поле для ветвления — см. Оплата.

Одно из:completedpayment_required
Пример ответа
{
  "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"
}

Управление серверами

Каждый метод здесь принимает сервер по id — в этих вызовах поле буквально называется id, в отличие от vps_id у денежных методов.

POST

ListVPS

read
https://apiservice.vitamindata.net/api/v1/ListVPS

Ваши машины, с состоянием питания и адресами.

Запрос
limitintнеобязательно

Размер страницы. По умолчанию 50.

cursorcursorнеобязательно

next_cursor из предыдущего ответа. Для первой страницы опустите.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/ListVPS \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"limit":50,"cursor":""}'
Ответ200 · application/json
vpsarray

Ваши машины.

vps[].idstring

Идентификатор сервера — его принимают id каждого метода управления и vps_id каждого денежного метода.

vps[].namestring

Её имя хоста / метка.

vps[].node_idstring

Где она работает.

vps[].lifecycleenum

0 разворачивается · 1 активна · 2 приостановлена · 3 удаляется · 4 удалена.

Одно из:01234
vps[].provisionedbool

Машина существует на своём хосте.

vps[].power_desiredenum

Каким питание ДОЛЖНО быть: 1 — включено, 0/отсутствует — выключено. Реальное состояние — GetVPSStats.running.

Одно из:01
vps[].vcpuint

Ядра.

vps[].mem_mbint

Память в МБ.

vps[].disk_gbint

Диск в ГБ.

vps[].image_shastring

С чего она загрузилась или установилась.

vps[].expires_atunix

Когда сервер истекает — продлите через ExtendVPS до этого момента.

vps[].created_atunix

Когда она была создана.

vps[].ipsarray

Её публичные адреса.

vps[].private_ipstring

Её приватный адрес, если он предусмотрен тарифом.

next_cursorcursor

Верните его как cursor, чтобы получить следующую страницу. Отсутствует/пустой = вы получили всё.

Пример ответа
{
  "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"
  }]
}
POST

GetVPS

read
https://apiservice.vitamindata.net/api/v1/GetVPS

Одна машина подробно.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetVPS \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"id":"vm_7q3k1n"}'
Ответ200 · application/json
vpsobject

Машина.

vps.idstring

Идентификатор сервера — его принимают id каждого метода управления и vps_id каждого денежного метода.

vps.namestring

Её имя хоста / метка.

vps.node_idstring

Где она работает.

vps.lifecycleenum

0 разворачивается · 1 активна · 2 приостановлена · 3 удаляется · 4 удалена.

Одно из:01234
vps.provisionedbool

Машина существует на своём хосте.

vps.power_desiredenum

Каким питание ДОЛЖНО быть: 1 — включено, 0/отсутствует — выключено. Реальное состояние — GetVPSStats.running.

Одно из:01
vps.vcpuint

Ядра.

vps.mem_mbint

Память в МБ.

vps.disk_gbint

Диск в ГБ.

vps.image_shastring

С чего она загрузилась или установилась.

vps.expires_atunix

Когда сервер истекает — продлите через ExtendVPS до этого момента.

vps.created_atunix

Когда она была создана.

vps.ipsarray

Её публичные адреса.

vps.private_ipstring

Её приватный адрес, если он предусмотрен тарифом.

livebool

Только что прочитано из системы.

Пример ответа
{
  "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
}
POST

GetVPSStats

read
https://apiservice.vitamindata.net/api/v1/GetVPSStats

CPU, память, диск и сеть в реальном времени.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetVPSStats \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"id":"vm_7q3k1n"}'
Ответ200 · application/json
cpu_pctint

Загрузка CPU, в процентах.

mem_used_mbint

Занятая память, МБ.

disk_used_mbint

Занятый диск, МБ.

rx_bpsint64

Входящий, бит в секунду.

tx_bpsint64

Исходящий, бит в секунду.

runningbool

Машина прямо сейчас включена.

updated_atunix

Когда были сняты эти показатели.

Пример ответа
{
  "cpu_pct": 12,
  "mem_used_mb": 1536,
  "disk_used_mb": 9216,
  "rx_bps": "1048576",
  "tx_bps": "524288",
  "running": true,
  "updated_at": "1785412790"
}
POST

GetVPSUsage

read
https://apiservice.vitamindata.net/api/v1/GetVPSUsage

Трафик, израсходованный из квоты машины, по пакетам.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/GetVPSUsage \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"id":"vm_7q3k1n"}'
Ответ200 · application/json
total_downbytes

Скачано за всё время.

total_upbytes

Отдано за всё время.

bundlesarray

Пакеты трафика; current помечает тот, что расходуется сейчас.

bundles[].idint64

Идентификатор пакета трафика в вычислительной системе.

bundles[].modeint

Код режима учёта этой системы. Считайте непрозрачным.

bundles[].bytes_totalbytes

Полная квота пакета.

bundles[].used_dlbytes

Скачано в счёт него.

bundles[].used_upbytes

Отдано в счёт него.

bundles[].stateint

Код состояния этой системы. Считайте непрозрачным.

bundles[].currentbool

Это пакет, который расходуется прямо сейчас.

bundles[].expires_atunix

Когда пакет истекает.

Пример ответа
{
  "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"}
  ]
}
POST

VPSPower

manage
https://apiservice.vitamindata.net/api/v1/VPSPower

Управление питанием.

shutdown просит операционную систему; force_stop выдёргивает питание. Предпочитайте первое.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

actionenumобязательное

shutdown/reboot — корректные; reset/force_stop — кнопка питания.

Одно из:startshutdownrebootresetforce_stop
Пример запроса
curl https://apiservice.vitamindata.net/api/v1/VPSPower \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"id":"vm_7q3k1n","action":"reboot"}'
Ответ200 · application/json
okbool

Система приняла действие. Следите за фактическим состоянием машины через GetVPSStats.

Пример ответа
{"ok": true}
POST

ReinstallVPS

manage
https://apiservice.vitamindata.net/api/v1/ReinstallVPS

Стирает диск и устанавливает свежий образ.

Разрушающая операция, НЕ безопасная для повтора — один вызов, одна переустановка. Образ должен уместиться на текущий диск; если нет, сначала увеличьте диск.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

image_shastringобязательное

Образ, по sha из ListVPSImages. Другого способа указать образ нет, а sha не из каталога отклоняется.

reset_rootboolнеобязательно

Заодно сгенерировать новый пароль root.

Пример запроса
curl 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}'
Ответ200 · application/json
okbool

Система приняла действие. Следите за фактическим состоянием машины через GetVPSStats.

Пример ответа
{"ok": true}
POST

AttachVPSISO

manage
https://apiservice.vitamindata.net/api/v1/AttachVPSISO

Подключает установочный ISO. Чтобы загрузиться с него, задайте порядок загрузки 1.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

image_shastringобязательное

Образ, по sha из ListVPSImages. Другого способа указать образ нет, а sha не из каталога отклоняется.

Пример запроса
curl 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"}'
Ответ200 · application/json
okbool

Система приняла действие. Следите за фактическим состоянием машины через GetVPSStats.

Пример ответа
{"ok": true}
POST

DetachVPSISO

manage
https://apiservice.vitamindata.net/api/v1/DetachVPSISO

Отключает ISO и возвращает загрузку с диска.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

Пример запроса
curl https://apiservice.vitamindata.net/api/v1/DetachVPSISO \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"id":"vm_7q3k1n"}'
Ответ200 · application/json
okbool

Система приняла действие. Следите за фактическим состоянием машины через GetVPSStats.

Пример ответа
{"ok": true}
POST

SetVPSBootOrder

manage
https://apiservice.vitamindata.net/api/v1/SetVPSBootOrder

Какое устройство загружается первым.

Запрос
idstringобязательное

Идентификатор сервера, из ListVPS. Обратите внимание: у методов управления поле называется id — только денежные методы пишут его как vps_id.

orderenumобязательное

0 — сначала диск, 1 — сначала CD-ROM.

Одно из:01
Пример запроса
curl https://apiservice.vitamindata.net/api/v1/SetVPSBootOrder \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"id":"vm_7q3k1n","order":1}'
Ответ200 · application/json
okbool

Система приняла действие. Следите за фактическим состоянием машины через GetVPSStats.

Пример ответа
{"ok": true}