Vitamin API 参考

在你自己的网站、机器人或脚本里销售并管理 VPN 账号与虚拟服务器。

基础 URLhttps://apiservice.vitamindata.net/api/v1

密钥在你的面板中创建。如果看不到该栏目,请联系支持为你的账户开启 API 访问。

1

在你的面板中创建 API 密钥,并在每次调用时作为 bearer token 发送。

2

调用 Ping 验证密钥,然后用 ListPlansGetVPSStorefront 拉取你的价格。

3

FUNDING_AUTO 销售:余额够时从余额扣款,不够时你的客户会得到一个支付链接。

身份验证

每个请求都以 bearer token 的形式携带你的密钥。此主机上没有 cookie,也不需要获取 CSRF token —— 密钥就是全部凭据。

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 直到状态变为 deliveredpayment_required 表示把客户引导到 pay_url;账单支付后交付会自动开始。

价格始终由我们决定。你可以发送 expected_total_usd 作为保护:如果我们最新的报价不同,这笔销售会以 price_changed 和新的总额被拒绝,而不是按客户从未看到的金额收费。

安全重试

每一个花钱的调用都请发送 Idempotency-Key 头。如果响应始终没有到达你 —— 超时、连接中断、进程重新部署 —— 用相同的键重发相同的请求,你会拿回最初的结果,而不是第二次扣款。

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

每个客户动作用一个新的键(UUID 最理想)。用同一个键搭配不同的请求体会以 idempotency_conflict 被拒绝 —— 这种组合意味着代码有 bug,猜测你想要哪一个请求比直接告知你更糟。

速率限制

每个已通过身份验证的响应都会告诉你,你这把密钥当前的额度状况:

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

限制按密钥、按分钟计算,并针对你的账户设定 —— 默认值适合一个店面;繁忙的机器人应当申请更高的额度,而不是把自己压到默认值。超出后会返回带 Retry-After429

如果来自同一地址的大量请求身份验证失败,也会出现 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 是 base64 编码的 protobuf(忽略它 —— 读 debug);而 debug 里的附加字段是 lowerCamelCase —— payUrlorderIdtotalUsdretryAfterSeconds —— 这是 Connect 的约定,与其他地方的 snake_case 不同。请根据顶层的 messagedebug.code 来分支;绝不要根据那句描述文字。

请求获得授权之前的拒绝

一个根本没走到处理逻辑的请求 —— 缺少密钥或密钥有误(401)、密钥不允许的来源地址(403)、触到速率限制(429)、身份验证服务中断(503)—— 会在入口处就被拒绝,而入口返回的响应体更短:只有一个传输层 code 和一句普通的描述文字,没有 details,也没有机器码。

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

所以对这些情况请按 HTTP 状态码分支(并遵守 Retry-After429 会带上这个头);下面的机器码只属于已经走到处理逻辑的调用。那道粗粒度的按地址限速闸更老,它返回的是 {"error":"rate_limited"} —— 键名是 error,不是 code

代码含义该怎么做
forbidden_scope密钥没有此调用所需的权限,或者这个操作已被禁用。请联系支持扩大密钥的权限。
not_found在此账户下没有这个对象。检查 id。属于他人的 id 也会得到同样的响应 —— 这是刻意设计。
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 提供给支持。

约定

  • 传输方式。每个调用都是带 JSON 请求体的 POST {base}/{Method} —— POST /api/v1/CreateVPNOrder。除此之外什么都没有:其他任何 HTTP 方法都会得到 405,不存在 REST 动词映射,也没有路径参数。
  • 金额是字符串。"19.99",绝不是 19.99:JSON 数字在大多数语言里是浮点数,无法精确表示一分钱。
  • 64 位整数以字符串形式到达。每个字节数和每个 unix 时间戳都是 64 位的,线路上会给它们加引号 —— "remaining_bytes": "96636764160"。请把它们解析为整数;在请求中两种形式都可以发送。
  • 零值会被省略。值为 0false 或为空的字段根本不会出现在响应中。把缺失当作零 —— 并且记住,每日上限为 0 表示没有上限,而不是“0 GB”。
  • 时间是 unix 秒,唯一的例外是交易查询窗口,它接受并返回 RFC3339 或 YYYY-MM-DD
  • 流量一律以字节计,任何数字都绝不是 GB。
  • id 是不透明的。acc_…ord_…vpn_…。永远不要解析或自行生成 id,也不要假定它们是连续的。
  • 分页使用不透明游标:把上一次响应的 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

返回你的账户 id、密钥是正式的还是测试的,以及我们的时间。

请求

没有参数 —— 发送一个空对象 {}。

请求示例
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

你账户的邮箱、状态、语言,以及邮箱是否已验证。

请求

没有参数 —— 发送一个空对象 {}。

请求示例
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

公开 id(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

账本行的 id。

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

网关的账单 id(inv_…)。

invoice.statusenum

pending 表示可支付。从 confirmeddelivered_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

网关的账单 id(inv_…)。

invoice.statusenum

pending 表示可支付。从 confirmeddelivered_redirected 的所有状态都表示钱已不可逆地到账 —— 把它们全部当作已支付。expired 表示链接在未支付的情况下已失效。

取值之一:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

托管的支付页面。把客户引导到这里;所有支付通道(币种、链、余额)都在它后面。

invoice.pay_telegram_urlstring

同一张账单,可在 Telegram 内支付:它会打开支付服务商自己的机器人,由机器人显示金额并在那里收款。把它放在 pay_url 旁边,供不愿离开应用的客户使用。可能缺失 —— 只有配置了机器人的支付服务商才有,所以绝不要把它当作你唯一的支付按钮。

invoice.price_usdmoney

账单收取的金额。

invoice.expires_atunix

支付窗口的关闭时间。

paymentsarray

链上所显示的内容。余额支付的账单(不涉及链)以及尚无人支付的账单都为空 —— 空列表不是错误。

payments[].chainstring

付款到达的网络(tronbsc 等)。

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 放进购物车;滑块购物车使用 gb/月数/用户数。

请求

没有参数 —— 发送一个空对象 {}。

请求示例
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

每日上限,以 GB 计。缺失 = 没有。

响应示例
{
  "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可选

每个账号的流量,以 GB 计,须在 ListPlans 给出的边界内。

cart.monthsint可选

每个账号的有效期,以月计。

cart.usersint可选

每个账号的并发设备数。

cart.new_accountsint可选

仅限 kind:"new":要创建多少个账号。用户名由服务端生成。

cart.extend_vpn_idsarray可选

仅限 kind:"extend":要续期的账号,按公开 id。

cart.bundle_idstring可选

购买 ListPlans.bundles 中的固定价格卡片,而不是自行配置的购物车。设置后 gb/月数/用户数会被忽略 —— 以卡片自身的取值和价格为准。

请求示例
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

该行的类别,供你的 UI 分组。

quote.lines[].amount_usdmoney

带符号。折扣为负;各行加总恰好等于 total_usd

quote.lines[].pctstring

该行背后的百分比(如果有)。

quote.cappedbool

总额触到了定价模型的上限。

quote.floor_appliedbool

总额被抬高到定价模型的下限。

quote.clampedenum

当购物车的某个取值在定价前被限制回边界内时设置。

取值之一:minmax
quote.invalidstring

非空表示该购物车无法定价 —— 把它展示出来,且绝不要按这样的报价收费。

quote.metamap

模型附加信息,string→string(例如升级的 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可选

每个账号的流量,以 GB 计,须在 ListPlans 给出的边界内。

cart.monthsint可选

每个账号的有效期,以月计。

cart.usersint可选

每个账号的并发设备数。

cart.new_accountsint可选

仅限 kind:"new":要创建多少个账号。用户名由服务端生成。

cart.extend_vpn_idsarray可选

仅限 kind:"extend":要续期的账号,按公开 id。

cart.bundle_idstring可选

购买 ListPlans.bundles 中的固定价格卡片,而不是自行配置的购物车。设置后 gb/月数/用户数会被忽略 —— 以卡片自身的取值和价格为准。

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

订单的公开 id(ord_…)。

order.productenum

买的是什么。

取值之一:vpnvps
order.kindstring

购买的形式:newextendupgrade……

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

网关的账单 id(inv_…)。

invoice.statusenum

pending 表示可支付。从 confirmeddelivered_redirected 的所有状态都表示钱已不可逆地到账 —— 把它们全部当作已支付。expired 表示链接在未支付的情况下已失效。

取值之一:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

托管的支付页面。把客户引导到这里;所有支付通道(币种、链、余额)都在它后面。

invoice.pay_telegram_urlstring

同一张账单,可在 Telegram 内支付:它会打开支付服务商自己的机器人,由机器人显示金额并在那里收款。把它放在 pay_url 旁边,供不愿离开应用的客户使用。可能缺失 —— 只有配置了机器人的支付服务商才有,所以绝不要把它当作你唯一的支付按钮。

invoice.price_usdmoney

账单收取的金额。

invoice.expires_atunix

支付窗口的关闭时间。

paidbool

钱已收讫。状态为 payment_required 时缺失(= false)。

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

订单的公开 id(ord_…)。

order.productenum

买的是什么。

取值之一:vpnvps
order.kindstring

购买的形式:newextendupgrade……

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

订单的公开 id(ord_…)。

orders[].productenum

买的是什么。

取值之一:vpnvps
orders[].kindstring

购买的形式:newextendupgrade……

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 动词都使用的公开 id。

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必填

账号的公开 id(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 动词都使用的公开 id。

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必填

账号的公开 id(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 1live:false 表示我们读不到它们,这与“没有”不是一回事。

请求
vpn_idstring必填

账号的公开 id(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

该钱包的 id。

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

售出时标称的大小,以 GB 计。

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

修改账号的密码。

需要单独的 credentials 权限 —— manage 从不隐含它。

请求
vpn_idstring必填

账号的公开 id(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必填

账号的公开 id(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必填

账号的公开 id(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

内存,以 MB 计。

nodes[].plans[].disk_gbint

磁盘,以 GB 计。

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

供你的 UI 分组和显示图标之用。

取值之一: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 标识。

购物车、重装和挂载 ISO 都接受这个 sha。除此之外没有任何东西能标识一个镜像。

请求

没有参数 —— 发送一个空对象 {}。

请求示例
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

供你的 UI 分组和显示图标之用。

取值之一: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可选

在套餐之外追加的磁盘,以 GB 计。

cart.extra_ipsint可选

额外的公网 IPv4 地址。

cart.extra_traffic_tbmoney可选

额外的每月流量,以 TB 计,十进制字符串("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

该行的类别,供你的 UI 分组。

quote.lines[].amount_usdmoney

带符号。折扣为负;各行加总恰好等于 total_usd

quote.lines[].pctstring

该行背后的百分比(如果有)。

quote.cappedbool

总额触到了定价模型的上限。

quote.floor_appliedbool

总额被抬高到定价模型的下限。

quote.clampedenum

当购物车的某个取值在定价前被限制回边界内时设置。

取值之一:minmax
quote.invalidstring

非空表示该购物车无法定价 —— 把它展示出来,且绝不要按这样的报价收费。

quote.metamap

模型附加信息,string→string(例如升级的 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可选

在套餐之外追加的磁盘,以 GB 计。

cart.extra_ipsint可选

额外的公网 IPv4 地址。

cart.extra_traffic_tbmoney可选

额外的每月流量,以 TB 计,十进制字符串("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

订单的公开 id(ord_…)。

order.productenum

买的是什么。

取值之一:vpnvps
order.kindstring

购买的形式:newextendupgrade……

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

网关的账单 id(inv_…)。

invoice.statusenum

pending 表示可支付。从 confirmeddelivered_redirected 的所有状态都表示钱已不可逆地到账 —— 把它们全部当作已支付。expired 表示链接在未支付的情况下已失效。

取值之一:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

托管的支付页面。把客户引导到这里;所有支付通道(币种、链、余额)都在它后面。

invoice.pay_telegram_urlstring

同一张账单,可在 Telegram 内支付:它会打开支付服务商自己的机器人,由机器人显示金额并在那里收款。把它放在 pay_url 旁边,供不愿离开应用的客户使用。可能缺失 —— 只有配置了机器人的支付服务商才有,所以绝不要把它当作你唯一的支付按钮。

invoice.price_usdmoney

账单收取的金额。

invoice.expires_atunix

支付窗口的关闭时间。

paidbool

钱已收讫。状态为 payment_required 时缺失(= false)。

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必填

服务器的 id,来自 ListVPS

monthsint必填

要增加多少个月。店面的 months_minmonths_max 是你的 UI 应当提供的范围,但续费并不会把它限制回这个区间 —— 请发送一个合理的数字,因为你发多少,就按多少定价和收费。

请求示例
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

该行的类别,供你的 UI 分组。

quote.lines[].amount_usdmoney

带符号。折扣为负;各行加总恰好等于 total_usd

quote.lines[].pctstring

该行背后的百分比(如果有)。

quote.cappedbool

总额触到了定价模型的上限。

quote.floor_appliedbool

总额被抬高到定价模型的下限。

quote.clampedenum

当购物车的某个取值在定价前被限制回边界内时设置。

取值之一:minmax
quote.invalidstring

非空表示该购物车无法定价 —— 把它展示出来,且绝不要按这样的报价收费。

quote.metamap

模型附加信息,string→string(例如升级的 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必填

服务器的 id,来自 ListVPS

monthsint必填

要增加多少个月。店面的 months_minmonths_max 是你的 UI 应当提供的范围,但续费并不会把它限制回这个区间 —— 请发送一个合理的数字,因为你发多少,就按多少定价和收费。

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

订单的公开 id(ord_…)。

order.productenum

买的是什么。

取值之一:vpnvps
order.kindstring

购买的形式:newextendupgrade……

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

网关的账单 id(inv_…)。

invoice.statusenum

pending 表示可支付。从 confirmeddelivered_redirected 的所有状态都表示钱已不可逆地到账 —— 把它们全部当作已支付。expired 表示链接在未支付的情况下已失效。

取值之一:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

托管的支付页面。把客户引导到这里;所有支付通道(币种、链、余额)都在它后面。

invoice.pay_telegram_urlstring

同一张账单,可在 Telegram 内支付:它会打开支付服务商自己的机器人,由机器人显示金额并在那里收款。把它放在 pay_url 旁边,供不愿离开应用的客户使用。可能缺失 —— 只有配置了机器人的支付服务商才有,所以绝不要把它当作你唯一的支付按钮。

invoice.price_usdmoney

账单收取的金额。

invoice.expires_atunix

支付窗口的关闭时间。

paidbool

钱已收讫。状态为 payment_required 时缺失(= false)。

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必填

服务器的 id,来自 ListVPS

specobject必填

目标配置。省略/为零的字段保持当前值。

spec.vcpuint可选

目标核心数。0 保持当前值。

spec.ram_mbint可选

目标内存,以 MB 计。0 保持当前值。

spec.disk_gbint可选

目标磁盘大小,以 GB 计。磁盘只能变大 —— 更小的值会被拒绝,因为在运行中的操作系统之下收缩文件系统等于丢数据。

请求示例
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

该行的类别,供你的 UI 分组。

quote.lines[].amount_usdmoney

带符号。折扣为负;各行加总恰好等于 total_usd

quote.lines[].pctstring

该行背后的百分比(如果有)。

quote.cappedbool

总额触到了定价模型的上限。

quote.floor_appliedbool

总额被抬高到定价模型的下限。

quote.clampedenum

当购物车的某个取值在定价前被限制回边界内时设置。

取值之一:minmax
quote.invalidstring

非空表示该购物车无法定价 —— 把它展示出来,且绝不要按这样的报价收费。

quote.metamap

模型附加信息,string→string(例如升级的 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必填

服务器的 id,来自 ListVPS

specobject必填

目标配置 —— 请先报价;报价也会告诉你是否需要重启。

spec.vcpuint可选

目标核心数。0 保持当前值。

spec.ram_mbint可选

目标内存,以 MB 计。0 保持当前值。

spec.disk_gbint可选

目标磁盘大小,以 GB 计。磁盘只能变大 —— 更小的值会被拒绝,因为在运行中的操作系统之下收缩文件系统等于丢数据。

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

订单的公开 id(ord_…)。

order.productenum

买的是什么。

取值之一:vpnvps
order.kindstring

购买的形式:newextendupgrade……

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

网关的账单 id(inv_…)。

invoice.statusenum

pending 表示可支付。从 confirmeddelivered_redirected 的所有状态都表示钱已不可逆地到账 —— 把它们全部当作已支付。expired 表示链接在未支付的情况下已失效。

取值之一:pendingconfirmedsweepingsweptdeliveringdelivereddelivered_redirectedexpired
invoice.pay_urlstring

托管的支付页面。把客户引导到这里;所有支付通道(币种、链、余额)都在它后面。

invoice.pay_telegram_urlstring

同一张账单,可在 Telegram 内支付:它会打开支付服务商自己的机器人,由机器人显示金额并在那里收款。把它放在 pay_url 旁边,供不愿离开应用的客户使用。可能缺失 —— 只有配置了机器人的支付服务商才有,所以绝不要把它当作你唯一的支付按钮。

invoice.price_usdmoney

账单收取的金额。

invoice.expires_atunix

支付窗口的关闭时间。

paidbool

钱已收讫。状态为 payment_required 时缺失(= false)。

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 —— 所有管理动词的 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

内存,以 MB 计。

vps[].disk_gbint

磁盘,以 GB 计。

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必填

服务器的 id,来自 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 —— 所有管理动词的 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

内存,以 MB 计。

vps.disk_gbint

磁盘,以 GB 计。

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必填

服务器的 id,来自 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

内存已用量,MB。

disk_used_mbint

磁盘已用量,MB。

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必填

服务器的 id,来自 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

流量包在计算平面上的 id。

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必填

服务器的 id,来自 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必填

服务器的 id,来自 ListVPS。注意管理动词上的字段名是 id —— 只有花钱的动词写作 vps_id

image_shastring必填

镜像,用 ListVPSImages 里的 sha 指定。除此之外没有别的方式标识镜像,不在目录中的 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必填

服务器的 id,来自 ListVPS。注意管理动词上的字段名是 id —— 只有花钱的动词写作 vps_id

image_shastring必填

镜像,用 ListVPSImages 里的 sha 指定。除此之外没有别的方式标识镜像,不在目录中的 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必填

服务器的 id,来自 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必填

服务器的 id,来自 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}