Vio eSIM
REST API · v1

Vio eSIM API 参考文档

同一后端提供两套 REST 接口:驱动网页版与我们 iOS/Android 应用的面向客户 API,以及一套单独的、通过 API 密钥认证的合作伙伴 API,用于以编程方式转售 Vio eSIM。

移动端 / 网页 API
https://vioesim.com/api/v1
合作伙伴 API
https://vioesim.com/api/public/v1

移动应用身份验证

网页版和原生应用共享同一套会话系统——原生应用只是自行携带令牌,而不依赖 Cookie。

注册或登录。 两个接口都会在用户对象旁返回一个 token 字段(以及网页版改用的 Set-Cookie 头)。请将 token 存储在 Keychain(iOS)或 Keystore 支持的存储中(Android)。

在每次请求中 将其带回:

Authorization: Bearer <token>

令牌有效期: 自签发起 30 天,或直到调用 /api/v1/auth/logout。没有刷新令牌步骤——即将过期的令牌只需让用户重新登录即可替换。

被暂停、封禁或已删除账户的会话会立即停止工作——服务器会在每次请求时进行检查,即使令牌本身尚未过期。

合作伙伴 API 身份验证

面向通过自有网站或应用转售 Vio eSIM 的外部企业。合作伙伴就是一个普通的 Vio eSIM 账户:从以下位置生成密钥 控制台 → API 密钥 (仅显示一次——请妥善保存,无法再次查看),然后在每次请求中发送:

Authorization: Bearer vio_live_sk_...
# or
X-API-Key: vio_live_sk_...

生成新密钥会立即使之前的密钥失效。

计费模式: 合作伙伴 API 的订单会同步从账户的预付钱包余额中扣款——由于这是服务器对服务器的调用,因此没有结账跳转。请先在控制台充值(银行卡/加密货币)再下单;余额不足时 POST /orders 将返回 402。

快速入门 — 合作伙伴 API

两次调用即可浏览目录并购买 eSIM:

curl https://vioesim.com/api/public/v1/destinations \
  -H "Authorization: Bearer vio_live_sk_..."

curl -X POST https://vioesim.com/api/public/v1/orders \
  -H "Authorization: Bearer vio_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "planId": "cus...", "quantity": 1 }'

错误与速率限制

移动端/网页 API 返回 { "error": "消息" }(目前为土耳其语消息)。合作伙伴 API 返回结构化格式,方便你根据 code 分支处理:

{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient wallet balance." } }
状态码含义
401缺失/无效/过期的令牌或 API 密钥
402仅合作伙伴 API — 钱包余额不足
404资源不存在,或不属于调用方
409状态冲突(例如删除余额不为零的账户)
429触发速率限制 — 参见 Retry-After 响应头(秒)
502已扣款但 eSIM 开通失败 — 请勿重复扣款

速率限制(合作伙伴 API): 读取接口每个密钥每分钟 120 次,POST /orders 每分钟 30 次。

移动端 / 网页 API

身份验证

POST/api/v1/auth/register无需认证

注册

创建账户并建立活跃会话。

Request body
{
  "firstName": "Ada",
  "lastName": "Lovelace",
  "email": "[email protected]",
  "password": "min 8 chars"
}
200 OK
{
  "success": true,
  "user": {
    "id", "firstName", "lastName", "fullName", "email",
    "emailVerified", "walletBalance", "currency", "locale", "createdAt"
  },
  "token": "..."
}
POST/api/v1/auth/login无需认证

登录

请求体:{ email, password }。响应格式与注册相同。凭据错误返回 401,账户被暂停返回 403。

POST/api/v1/auth/logout会话令牌

登出

无请求体。在服务器端删除会话——请在真正登出时调用,而不仅仅是"本地忘记令牌",这样被盗令牌就无法继续使用。

GET/api/v1/auth/me会话令牌 · 可选

当前用户

未登录时返回 { "user": null }(绝不是错误)——可在应用启动时用此判断是否显示登录界面。

POST/api/v1/auth/forgot-password无需认证

忘记密码

请求体:{ email, locale }。无论该邮箱是否存在都返回 { success: true },以防止枚举账户。会发送包含重置链接/令牌的邮件(1 小时内有效)。

POST/api/v1/auth/reset-password无需认证

重置密码

请求体:{ token, newPassword }。使用 ?token= 发起 GET 请求可在显示表单前校验有效性({ "valid": true|false })。

POST/api/v1/auth/change-password会话令牌

修改密码

请求体:{ currentPassword, newPassword }。除非账户尚未设置密码(如社交登录),否则 currentPassword 为必填项。

账户

PATCH/api/v1/user/profile会话令牌

更新资料

只需发送你想修改的字段。

FieldNotes
firstName, lastName可选 · 字符串
preferredCurrency可选 · USD、EUR、GBP、TRY 之一
locale可选 · 两字母代码,如 zh
200 OK
{ "success": true, "user": { ...same shape as /auth/me } }
POST/api/v1/user/avatar会话令牌

更新头像

请求体:{ "avatarUrl": "data:image/..." } — base64 data URI,最大约 1.5MB。

POST/api/v1/user/api-key/generate会话令牌

生成 API 密钥

为该账户签发新的合作伙伴 API 密钥,替换先前的密钥。原始密钥仅在此响应中显示一次——之后只能获取其前缀。

200 OK
{
  "success": true,
  "key": "vio_live_sk_...",
  "apiKeyPrefix": "vio_live_sk_ab12…9f8e",
  "apiKeyGeneratedAt": "2026-08-22T17:00:00.781Z"
}
DELETE/api/v1/user/account会话令牌

删除账户

App Store 审核所需(提供账户创建功能的应用必须提供应用内注销)。会匿名化账户(邮箱被打乱并释放以供重新注册,姓名/头像/密码被清除),而不是永久删除记录,以便过往订单保留用于税务/记账用途。会销毁该用户的所有会话及已注册的推送设备。

若 walletBalance > 0 则返回 409 — 应用应先提示用户提现或联系客服,而不是让余额被静默没收。

目录

GET/api/v1/destinations无需认证

获取目的地列表

拥有有效套餐的国家和地区,已定价并按 UI 格式化(这正是商城本身调用的接口)。可选 ?filter=popular|regional|global|<搜索文本>。

GET/api/v1/destinations/:code无需认证

目的地详情

按 ISO 代码获取某一国家的完整详情(描述、套餐),如 /api/v1/destinations/jp。

购买

POST/api/v1/checkout会话令牌

结账

直接购买套餐(而非先充值到钱包)。

FieldNotes
planId*
quantity可选 · 1–10,默认 1
paymentMethod*wallet | stripe | crypto
successUrl, cancelUrl可选 · 用于 stripe/crypto 跳转。请使用通用链接/应用链接,而非普通网页 URL,以便跳转能重新打开应用。
200 OK — wallet (synchronous)
{ "success": true, "orderId": "..." }
200 OK — stripe / crypto (redirect required)
{ "success": true, "orderId": "...", "url": "https://checkout.stripe.com/..." }
请在应用内浏览器(SFSafariViewController / Chrome Custom Tabs)中打开 url,而非普通 WebView — Stripe 和 Cryptomus 都需要真实的浏览器环境。
POST/api/v1/payments/stripe/create-session会话令牌

Stripe 钱包充值

通过银行卡为钱包充值 — 与结账是独立的流程。请求体:{ amount(美分,最小 200), currency, successUrl, cancelUrl }。返回 { sessionId, url }。

POST/api/v1/payments/cryptomus/create-invoice会话令牌

加密货币钱包充值

请求体:{ amount(十进制字符串,最小 $2), currency, url_return }。返回包含 url 的 Cryptomus 发票对象。

GET/api/v1/user/orders会话令牌

订单列表

调用方的所有订单,按最新到最旧排序。

GET/api/v1/user/orders/:id会话令牌

订单详情

单个订单,包含 esimIds — 可通过 GET /api/v1/user/esims 获取完整 eSIM 详情(二维码、激活码)并按 id 匹配。

GET/api/v1/user/esims会话令牌

我的 eSIM

调用方拥有的每个 eSIM:iccid、activationCode、qrCodeUrl、smdpAddress、status、dataUsage/totalVolume(MB)、activatedAt、expiresAt。这些数据驱动"我的 eSIM"界面和二维码显示。

GET/api/v1/user/wallet/transactions会话令牌

钱包历史

/auth/me 中显示的钱包余额对应的充值/提现/购买/退款历史。

客服

GET/api/v1/support/tickets会话令牌

工单列表

调用方的工单及完整消息记录,按最新到最旧排序。

POST/api/v1/support/tickets会话令牌

新建工单

请求体:{ subject, category, message }(category 可选)。

POST/api/v1/support/tickets/:id/messages会话令牌

回复工单

请求体:{ message }。回复 RESOLVED/CLOSED 状态的工单会自动重新打开该工单。

推送通知设备

仅注册设备令牌 — 实际发送推送还需要 APNs/FCM 凭据,见下方说明。

POST/api/v1/user/push-devices会话令牌

注册设备

在获取 APNs 或 FCM 令牌后调用。请求体:{ platform: "IOS"|"ANDROID", pushToken, appVersion }。按令牌执行 upsert,因此每次应用启动时重复调用是安全且建议的做法(令牌可能会轮换)。

DELETE/api/v1/user/push-devices会话令牌

注销设备

请求体:{ pushToken }。请在登出时调用,以防止共享/重置的设备继续接收其他用户的通知。

合作伙伴 API

以下所有接口均需使用上文所述的 API 密钥请求头 — 此处不适用会话 Cookie。

目录

GET/api/public/v1/destinationsAPI 密钥

获取目的地列表

完整目录,采用面向合作伙伴的格式(并非商城的 UI 格式)。

200 OK
{
  "countries": [
    {
      "code": "JP",
      "name": { "en": "Japan", "tr": "Japonya", "...": "..." },
      "flagEmoji": "🇯🇵",
      "continent": "Asia",
      "plans": [
        { "id": "cus...", "dataAmountMb": 1024, "durationDays": 7, "priceUsd": 4.25, "isTopUp": false }
      ]
    }
  ],
  "regions": [ { "code": "...", "name": {...}, "countryCount": 15, "plans": [...] } ]
}
GET/api/public/v1/destinations/:codeAPI 密钥

目的地详情

按 ISO 代码获取单个国家(如 /api/public/v1/destinations/JP),套餐格式与上文相同。

订单

POST/api/public/v1/ordersAPI 密钥

创建订单

从调用方钱包余额中扣款购买套餐,并同步开通 eSIM — 响应中已包含可直接交给最终客户的二维码/激活数据。正常情况下无需轮询。

Request body
{ "planId": "cus...", "quantity": 1 }
201 Created
{
  "id": "...", "orderNumber": "VIO-API-...", "status": "COMPLETED", "amountUsd": 4.25,
  "esims": [
    { "id": "...", "iccid": "...", "activationCode": "...",
      "qrCodeUrl": "https://...", "smdpAddress": "...", "status": "PENDING" }
  ]
}
失败情形:402 INSUFFICIENT_BALANCE(请先充值)、404 PLAN_NOT_FOUND,或 502 FULFILLMENT_FAILED(已扣款但供应商未能开通 eSIM — 响应中包含订单 id,客服已自动收到通知;请轮询 GET /orders/:id,切勿重复扣款)。
GET/api/public/v1/ordersAPI 密钥

订单列表

可选 ?limit=(默认 25,最大 100)。为摘要格式 — eSIM 数据请使用详情接口。

GET/api/public/v1/orders/:idAPI 密钥

订单详情

完整订单详情,包含每个 eSIM 的二维码/激活数据及实时用量(dataUsageMb / totalVolumeMb) — 轮询此接口可向客户展示其剩余流量。

钱包

GET/api/public/v1/walletAPI 密钥

钱包余额

批量下单前请先查询,或在余额过低时设置提醒。

200 OK
{ "balanceUsd": 128.40, "currency": "USD" }

尚未实现的功能

以确保此处不会将未实现的功能误认为已可用。

推送通知发送

令牌注册功能可用;实际发送推送还需要 APNs/FCM 凭据。

合作伙伴专属定价

合作伙伴 API 目前收取与商城相同的零售价。批发/协商定价需要修改数据结构并做出业务决策。

刷新令牌

会话是长期有效(30 天)的单一令牌,而非短期访问令牌 + 刷新令牌的组合。目前已足够;日后若需更严格的安全策略可重新评估。

原生 Stripe 支付界面

Stripe 集成目前使用托管 Checkout(跳转/内嵌网页)。原生的银行卡输入界面需改用 PaymentIntents 及 Stripe SDK。

面向合作伙伴的 Webhook

合作伙伴目前必须轮询 GET /orders/:id 获取状态;尚未提供出站 Webhook(例如"eSIM 已激活")。

Vio eSIM API参考文档与合作伙伴API文档