Tổng Kho eSIM
OpenAPI 2.4.0 · 30 项操作

API 参考

直接呈现后端生成规范中的全部 /v1 路径、参数、结构、枚举值和错误码,与服务端保持一致。

正式

https://api.tongkhoesim.com/v1

测试模式

https://api-testing.tongkhoesim.com/v1

正式环境:api.tongkhoesim.com / tke_live_(合作伙伴)或 tke_member_live_(已获授权会员)。测试:api-testing.tongkhoesim.com / tke_test_ / tke_member_test_(合作伙伴/会员)。

通用约定

以下 6 条规则适用于全部 30 项操作。

身份验证

包括 GET 在内,所有接口均需使用 4 个请求头(X-TKE-Key · X-TKE-Timestamp · X-TKE-Nonce · X-TKE-Signature)进行 HMAC-SHA256 签名。

响应封装
成功:{ ok: true, data };错误:{ ok: false, error: { code, message, field?, meta?, request_id } }。使用正确 HTTP 状态,失败不返回 200。
数据类型
金额为整数 VND(BIGINT),流量统一使用字节(含目录中的 data.total_bytes / data.daily_bytes),时间为 ISO-8601 UTC,展示时转换时区。
调用频率限制
429 包含 Retry-After 及 X-RateLimit-Limit / Remaining / Reset,请读取请求头,限制按密钥配置。
request_id
每个响应包含 X-Request-Id,错误中也有 error.request_id,请记录以便技术支持追踪。
Idempotency-Key

24 小时内相同密钥与请求体重放原结果,不重复扣款。范围为 api_key_id,以下 5 项操作必填:POST /v1/orders, POST /v1/orders/bulk, POST /v1/esims/{id}/cancel, POST /v1/esims/{id}/change-plan, POST /v1/esims/{id}/refund-requests。

两种分页方式

两种方式的响应结构和结束条件不同,请分别处理。

偏移分页 · page / page_size

仅用于 GET /v1/webhooks/deliveries,返回 page、page_size、total。

超出范围返回 HTTP 200、items: [] 和真实 total;列表为空或已处理 total 条时结束。

游标分页 · cursor / next_cursor

用于 /v1/catalog/packages、/v1/orders、/v1/esims、/v1/esims/{id}/plan-options,只有 orders 和 esims 支持 updated_since。

next_cursor 缺失或等于当前游标时结束,data 中可能完全不含此字段。

无效游标与 HTTP 200 的陷阱

为兼容旧客户端,无效游标会静默回到起点。仅判断 next_cursor !== null 可能无限重复第一页。

javascript
let cursor = null;
const seen = new Set();

while (true) {
  const params = new URLSearchParams({ page_size: "200" });
  if (cursor) params.set("cursor", cursor);

  // callSigned 为添加 4 个 X-TKE-* 请求头的辅助函数(参见 HMAC 页面)。
  const page = await callSigned("GET", `/v1/orders?${params}`);
  for (const order of page.data.items) await handle(order);

  const next = page.data.next_cursor;
  if (!next || next === cursor || seen.has(next)) break;
  seen.add(next);
  cursor = next;
}

目录

套餐目录为两个供应系统提供统一接口。供应系统通过字段(`market`: `domestic` | `international`)和筛选(`?market=`)区分,不再使用两个独立路径。 没有库存概念:不包含数量或 `available`/`low`/`out_of_stock` 等等级。套餐直接展示,若供应商无法交付,下单时由 `POST /v1/orders` 返回明确错误(如 `esim.out_of_stock`),而非目录提前告知。 统一使用游标分页。仅在统计成本低时(筛选国内系统)提供 `total`,否则为 `null`。

GET/v1/catalog/packages

列出套餐

scope catalog:readget_catalog_packages

所需权限范围: catalog:read.

您所属组织的套餐目录:两个供应系统共用一个接口,通过 ?market= 筛选。

仅返回实际可购买的套餐:已发布、供应商仍在分销、符合密钥目录限制,且已为组织定价。未定价套餐不显示是因为无法下单。

游标分页:首次不传 cursor,之后原样传回 next_cursor,直到为 null。当前页少于 page_size 条并不表示结束。

capabilities 来自套餐真实声明,绝不推测;未声明时全部标志为 false。宁可省略原本可用的按钮,也不承诺必然返回 422 的功能。

目录不包含库存概念,没有数量或有货/售罄等级。如果供应商无法交付,POST /v1/orders 会在下单时直接返回明确错误(如 esim.out_of_stock),无须从预先展示的字段推断。

查询参数 (18)

page_sizeinteger选填默认值 50min 1max 100

每页记录数,默认 50,上限 100;超过上限时限制为 100,不报错。

marketstring选填

供应系统:domestic | international。列表之外的值返回 internal.invalid_filter(400),而不是完整目录,避免将拼写错误误认为筛选没有排除任何记录。

countrystring选填

ISO-3166 alpha-2 国家代码(如 VN),仅返回覆盖该国的套餐。

regionstring选填

区域标识(如 chau-a),返回覆盖该区域至少一个国家的套餐及所有全球套餐。

qstring选填

按公开代码和套餐名称进行自由文本搜索(部分匹配,不区分大小写)。

tagstring选填

按一个商业标签筛选。与存储时使用相同的规范化方式:去除多余空格、转为小写并使用连字符,因此 Ban Le 与 ban-le 是同一标签。

data_modelstring选填

流量模型:daily | fixed | unlimited,替代旧 supports_topup。未知值返回 internal.invalid_filter(400)。

data_min_bytesinteger · int64选填

最低流量,单位为字节。按日套餐以每日额度比较;无限流量套餐始终满足下限条件。

data_max_bytesinteger · int64选填

最大流量,单位为字节。不包含无限流量套餐:流量上限不适用于无限套餐,若允许其通过筛选,寻找最小流量套餐的人也会获得无限套餐。

days_mininteger · int64选填

最短有效期,单位为天。

days_maxinteger · int64选填

最长有效期,单位为天。

price_mininteger · int64选填

最低价格(VND),与您所属组织的价格比较。此筛选在服务器分页后执行,因此页面记录减少不代表数据已经结束。

price_maxinteger · int64选填

最高价格(VND),规则与 price_min 相同。

network_genstring选填

仅查询支持该网络代际(2g | 3g | 4g | 5g)的套餐。未知值返回 internal.invalid_filter(400)。

hotspotstring选填
允许的值:truefalse

true 仅筛选明确支持热点的套餐,false 仅筛选明确不支持的套餐。未声明(features.hotspot = null)两边都不匹配。只接受字符串 true/false。

appstring选填

仅返回声明在至少一个操作系统上支持此应用的套餐(app=tiktok)。未声明的套餐不匹配,沉默不代表承诺。目前仅接受 tiktok,其他代码返回 internal.invalid_filter(400)。

voicestring选填
允许的值:truefalse

true 仅筛选明确支持语音的套餐,false 仅筛选明确不支持的套餐。未声明两边都不匹配。只接受字符串 true/false。

cursorstring选填

原样传回 next_cursor。仅在其为 null 时停止,不要因页面条目少而停止。 密钥目录限制、组织定价、价格范围筛选均在分页之后执行。游标含筛选条件指纹,条件改变或游标损坏返回 catalog.cursor_mismatch(400),避免拼接不同查询的页面。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
itemsobject[]
—
capabilitiesobject

套餐售后能力取自套餐实际声明,不根据供应商类型推断。未声明时所有标志为 false,避免承诺必然返回 422 capability.not_supported 的操作。

cancelobject
—
restrictionstring
可为 null

code_not_disclosed 表示仅在无人查看过激活码时可取消(包括未发送客户、未通过后台或 ?include=lpa 读取)。这是真实取消条件,与系统无法判断的安装状态无关。旧名称 unused_only 会造成错误承诺。

code_not_disclosednull
supportedboolean
—
plan_changeobject
—
policyobject
可为 null

此供应商追加新套餐时的处理方式。null 表示套餐无法追加,或尚未确认供应商政策,不能据此推断;全部字段为 false 的对象则表示保证不会取消任何套餐,两者含义不同。

……

还有更深层字段,请查看 JSON 示例。

supportedboolean
—
usage_checkobject
—
supportedboolean
—
codestring

您目录中的套餐代码,即 public_sku。每个套餐的代码不可变,更换底层供应商时也不变,因此可安全用作对账键。示例仅格式正确,无法实际调用;请从 GET /v1/catalog/packages 获取真实代码。

coverageobject

套餐可用地区。

countriesstring[]

ISO-3166 alpha-2 国家代码。全球套餐不逐一列出 200 个国家;全球套餐及未声明覆盖范围的套餐返回空数组。

country_countinteger

套餐覆盖的国家数量,可据此排序或筛选多国套餐,无须获取全部数据后自行统计数组。

groupstring

覆盖范围为国家列表(country)、地区(region)或全球(global)。开放枚举,必须忽略未知值。

regionstring
可为 null

始终为 null:地区关联国家而非套餐,填值将属于推断。仍可通过 ?region= 筛选。

dataobject

套餐流量额度,所有数值均以字节表示,而非 MB/GB,以避免重复舍入。

daily_bytesinteger · int64
可为 null

每日流量额度,单位为字节。fixed 或 unlimited 套餐为 null。

labelstring

由所有界面共用的函数生成的可读标签。

modelstring

流量计算方式:daily(每日额度)、fixed(整个有效期总量)或 unlimited。此枚举可扩展,客户端必须忽略未知值。

dailyfixedunlimited
resetobject
可为 null

每日额度重置时间。深夜购买时会影响首日可用时间,属于销售信息。null 表示未声明。

atstring
可为 null

按 timezone 所在时区表示的重置时间(00:00、00:00:01)。

notestring
可为 null
—
timezonestring
可为 null

重置时点的时区(UTC+8、UTC+7)。

total_bytesinteger · int64
可为 null

整个周期总流量(字节)。daily/unlimited 套餐为 null:每日额度乘天数并非供应商承诺的总量。

descriptionstring
可为 null

套餐销售说明,尚未填写时为 null。

description_enstring
可为 null

英文描述,尚未提供时为 null。

featuresobject

套餐能力采用带类型对象而非代码数组:[] 无法区分“不支持热点”和“信息未知”,false 与 null 可以。

appsobject[]

按操作系统区分的应用支持状态。

数组中不存在的应用表示信息未知,并非“支持”。 仅已列出的条目属于供应商承诺;目前只声明了 TikTok。

有意不提供合并字段:真实目录中有 2,465 个套餐支持 iPhone 上的 TikTok,但不支持 Android。一个合并标记会将其全部归为“不支持”,从而误判近三分之一的目录。

androidstring

supported(声明支持)、blocked(声明不支持)、unknown(声明未覆盖此操作系统)。开放枚举。

supportedblockedunknown
appstring

小写应用代码(例如 tiktok)。

iosstring

supported(声明支持)、blocked(声明不支持)、unknown(声明未覆盖此操作系统)。开放枚举。

supportedblockedunknown
notestring
可为 null
—
hotspotboolean
可为 null

向其他设备共享 Wi-Fi。null 表示未声明,与 false 不同。

kyc_requiredboolean
可为 null

使用前需要身份验证(KYC)。null 表示未声明。

smsboolean
可为 null

短信功能。false 表示无法接收短信,因此也无法接收银行验证码。null 表示未声明。

voiceboolean
可为 null

语音通话。false 表示供应商明确不支持语音,纯数据线路不能接听电话。null 表示未声明。

fupobject
可为 null

高速流量耗尽后的处理方式。null 表示未声明限速政策。

behaviorstring
可为 null

throttle(限速)、cutoff(断网)或 null(未声明)。开放枚举。

throttlecutoffnull
high_speed_bytesinteger · int64
可为 null

开始限速前可全速使用的字节数。

notestring
可为 null
—
speed_kbpsinteger
可为 null

高速额度用尽后的速率(kbps)。断网或未声明时为 null,不同于整个套餐的速率上限 network.speed_cap_kbps。

marketstring

套餐的供应系统,为可扩展枚举,客户端必须忽略未知值。它决定是否有库存及可用售后操作:domestic 销售套件,支持追加、取消和用量查询;international 按需向供应商下单,因此没有库存。

domesticinternational
namestring
—
name_enstring
可为 null

英文名称,尚未提供时为 null。

networkobject

套餐可用的网络。

apnstring
可为 null

某些无法自动配置的 Android 设备需要手动输入的 APN。此信息用于编写安装指南,否则每次都会变成客服咨询。null 表示未声明。

carriersobject[]

套餐实际使用的运营商网络。这是 eSIM 的无线网络规格,并非供应商。

namestring
—
generationsstring[]
可为 null

套餐可使用的网络代际(["4g", "5g"])。null 表示未声明,并非“仅支持 2G”。

speed_cap_kbpsinteger
可为 null

整个套餐的速率上限(kbps),不同于高速额度用尽后适用的 fup.speed_kbps。

priceobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
tagsstring[]

规范化的商业标签(小写、使用连字符),也用于匹配密钥的目录限制。目前没有套餐带标签,因此在卖方开始添加标签之前,?tag= 返回空列表。

validityobject

套餐有效期及开始计时的条件。

daysinteger
—
install_by_daysinteger
可为 null

购买后可扫描二维码或安装 eSIM 的天数。null 表示未声明,并非“随时可以安装”。

labelstring
—
reclaim_on_expiryboolean
可为 null

供应商在套餐到期时回收订阅,此后不能加购或换套餐。销售续费时需了解此窗口。null 表示未声明。

starts_whenstring
可为 null

计时起点:on_install(安装时)、on_purchase(购买时)或 null。这直接影响有效期计算;为 null 时不要承诺具体到期日期。

on_installon_purchasenull
unused_valid_daysinteger
可为 null

套餐未使用时可存放至过期的天数。null 表示未声明,并非无限期。此字段与 install_by_days 有意区分:一个是保管期限,一个是安装期限。

modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_cursorstring
可为 null

获取下一页时请原样传回。null 是唯一的结束信号,即使当前页少于 page_size 条,也可能仍有后续页面。

page_sizeinteger
可为 null

服务器用于本页的最大记录数,已应用上限,并非 items 中的实际元素数量。

totalinteger · int64
可为 null

匹配筛选条件的套餐总数。集合较大、计数成本高时(国际套餐或无 market 筛选)为 null。此计数发生在密钥限制及组织价格检查之前,表示目录匹配数而非可购数。

warningsobject[]

列表呈现方式的原因;无异常时为空。封闭代码集:filtered_by_key_package_filters、filtered_by_provider_scope、no_price_for_org、price_filter_removed_rows、provider_disabled、capability_missing,分别代表密钥限制、组织供应源范围、未定价、价格筛选、供应商停用、未声明功能。count 为涉及行数,无法量化时为 null。

codestring
—
filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing
countinteger · int64
可为 null
—
messagestring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failedinternal.invalid_filtercatalog.cursor_mismatch
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="GET"
REQ_PATH="/v1/catalog/packages"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "items": [
      {
        "capabilities": {
          "cancel": {
            "restriction": "code_not_disclosed",
            "supported": true
          },
          "plan_change": {
            "policy": {
              "note": "<note>",
              "requires_cancel_first": true,
              "stacking": true
            },
            "supported": true
          },
          "usage_check": {
            "supported": true
          }
        },
        "code": "TKE-VN-30D-X3K9F",
        "coverage": {
          "countries": [
            "CN"
          ],
          "country_count": 1,
          "group": "country",
          "region": "<region>"
        },
        "data": {
          "daily_bytes": 1073741824,
          "label": "1GB/ngày",
          "model": "daily",
          "reset": {
            "at": "00:00",
            "note": "<note>",
            "timezone": "UTC+8"
          },
          "total_bytes": null
        },
        "description": "<description>",
        "description_en": "<description_en>",
        "features": {
          "apps": [
            {
              "android": "blocked",
              "app": "tiktok",
              "ios": "supported",
              "note": "<note>"
            }
          ],
          "hotspot": true,
          "kyc_required": false,
          "sms": false,
          "voice": false
        },
        "fup": {
          "behavior": "throttle",
          "high_speed_bytes": 1048576,
          "note": "<note>",
          "speed_kbps": 128
        },
        "market": "international",
        "name": "eSIM Trung Quốc Mainland Multi - 1GB/ngày - 24 ngày",
        "name_en": "<name_en>",
        "network": {
          "apn": "e-ideas",
          "carriers": [
            {
              "name": "China Unicom"
            }
          ],
          "generations": [
            "4g",
            "5g"
          ],
          "speed_cap_kbps": 1
        },
        "price": {
          "amount": 273000,
          "currency": "VND"
        },
        "tags": [],
        "validity": {
          "days": 24,
          "install_by_days": 365,
          "label": "24 ngày",
          "reclaim_on_expiry": true,
          "starts_when": "on_install",
          "unused_valid_days": 1
        }
      }
    ],
    "mode": "live",
    "next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
    "page_size": 50,
    "total": 128,
    "warnings": []
  },
  "ok": true
}
GET/v1/catalog/packages/{code}

获取单个套餐

scope catalog:readget_catalog_packages__code_

所需权限范围: catalog:read.

按公开代码获取一个套餐的详情。data 的字段与 GET /v1/catalog/packages 单项相同,仅增加 mode;没有详情专属字段,因此只需定义一个 Package 类型。

无权查看的代码统一返回 partner.package_not_visible(404),无论原因是代码不存在、超出密钥目录限制、组织未定价或套餐失去供应关联。区分这些原因会让外部人员枚举整个目录。

路径参数 (1)

codestring必填

套餐代码,即目录中的 code(public_sku)。每个套餐不可变,更换底层供应商时不变,可保存为对账键。超出密钥目录限制或组织未定价的代码,与不存在的代码一样返回 404 partner.package_not_visible。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
partner.package_not_visible
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
CODE="THAY-BANG-CODE"

METHOD="GET"
REQ_PATH="/v1/catalog/packages/$CODE"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": null,
  "ok": true
}

订单

下单及对账

GET/v1/orders

列出订单(主动查询式对账)

scope orders:readget_orders

所需权限范围: orders:read.

查询参数 (5)

page_sizeinteger选填默认值 50min 1max 200

每页记录数,默认 50,上限 200;超过上限时限制为 200,不报错。

statusstring选填
允许的值:completedpending_providerprovider_failedcancelled

按订单状态筛选。列表之外的值返回 internal.invalid_filter(400)。

external_refstring选填

按提交订单时发送的参考编号筛选(精确匹配)。

updated_sincestring · date-time选填

ISO-8601 UTC 时间。按升序返回所有满足 updated_at >= updated_since 的记录,是标准主动查询式对账路径(§8.5);即使遗漏 webhook,也可从状态重建。格式错误返回 internal.invalid_filter(400)。

cursorstring选填

下一页游标,请原样传回上一页的 next_cursor。畸形游标不会报错,而会从列表开头读取,以兼容游标编码变更。请确认新游标与刚发送的值不同,避免无限循环读取第一页。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
itemsobject[]
—
created_atstring · date-time
—
external_refstring
可为 null
—
fulfillment_statusstring
—
fulfilledpartially_fulfilledunfulfilled
idstring · uuid
—
item_countinteger · int64
—
netobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
public_refstring
可为 null
—
refundedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
statusstring
—
totalobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
updated_atstring · date-time
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_cursorstring
可为 null

获取下一页时请原样传回。null 是唯一的结束信号,即使当前页少于 page_size 条,也可能仍有后续页面。

page_sizeinteger
可为 null

服务器用于本页的最大记录数,已应用上限,并非 items 中的实际元素数量。

totalinteger · int64
可为 null

符合筛选条件的记录数量。统计成本过高时为 null,请勿据此判断是否结束,应以 next_cursor 为准。

warningsobject[]

列表呈现方式的原因;无异常时为空。封闭代码集:filtered_by_key_package_filters、filtered_by_provider_scope、no_price_for_org、price_filter_removed_rows、provider_disabled、capability_missing,分别代表密钥限制、组织供应源范围、未定价、价格筛选、供应商停用、未声明功能。count 为涉及行数,无法量化时为 null。

codestring
—
filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing
countinteger · int64
可为 null
—
messagestring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failedinternal.invalid_filter
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="GET"
REQ_PATH="/v1/orders"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "items": [
      {
        "created_at": "2026-07-11T08:12:30Z",
        "external_ref": "po-1001",
        "fulfillment_status": "fulfilled",
        "id": "018f2b00-0000-7000-8000-00000000009a",
        "item_count": 2,
        "net": {
          "amount": 273000,
          "currency": "VND"
        },
        "public_ref": "TKE-DH-2A4C7Q",
        "refunded": {
          "amount": 273000,
          "currency": "VND"
        },
        "status": "completed",
        "total": {
          "amount": 273000,
          "currency": "VND"
        },
        "updated_at": "2026-07-11T09:03:11Z"
      }
    ],
    "mode": "live",
    "next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
    "page_size": 50,
    "total": 128,
    "warnings": []
  },
  "ok": true
}
POST/v1/orders

创建订单(直接购买)

scope orders:write必须提供 Idempotency-Keypost_orders

所需权限范围: orders:write.

请求头 (1)

Idempotency-Keystring必填

客户端生成的字符串:相同密钥和请求体只执行一次,重试返回原结果。范围为 api_key_id(§11),不同密钥属于不同命令。

请求体必填application/json

字段类型约束说明
external_refstring
可为 null

您的自定义引用代码,会原样回传至响应和 Webhook。

includestring[]
可为 null

请求额外区块:["lpa"] 或 ["lpa","qr"]。省略时 items[].install 为 null,订单中所有 eSIM 保留取消资格。返回代码即披露代码:请求 lpa 即接受订单创建时取消窗口立即关闭。

invoice_buyerobject
可为 null

仅适用于会员密钥。未填写时使用消费者流程,无需组织或越南法人。填写时按现有个人规则验证full_name、12位个人tax_code及结账address/email规则。企业发票在购买后申请。测试模式只验证快照,不签发MISA发票。

addressstring
可为 null
—
emailstring
可为 null
—
full_namestring
可为 null
—
legal_namestring
可为 null
—
tax_codestring
可为 null
—
itemsobject[]
必填

待购买套餐及数量列表(最多 50 个 eSIM)。

package_codestring
必填

您目录中的套餐代码,即 public_sku。每个套餐的代码不可变,更换底层供应商时也不变,因此可安全用作对账键。示例仅格式正确,无法实际调用;请从 GET /v1/catalog/packages 获取真实代码。

quantityinteger
必填

此套餐要购买的 eSIM 数量(≥ 1)。

响应

200重放已提交的订单

24 小时内使用相同 Idempotency-Key 和请求体重放:响应体与首次完全相同,不重复扣款,并添加 Idempotent-Replayed: true。新建返回 201,请勿仅凭此状态码区分成功。

字段类型约束说明
dataobject
必填

合作伙伴订单。

created_atstring · date-time
—
external_refstring
可为 null
—
fulfillment_statusstring

实际交付情况,与 status 是独立维度。订单含 3 个 eSIM,其中 2 个交付、1 个失败时,仍为 status=completed,同时 fulfillment_status=partially_fulfilled 且 refunded_amount > 0。

fulfilledpartially_fulfilledunfulfilled
idstring · uuid

订单 ID(UUID)。

idempotent_replayboolean
可为 null

此请求为先前成功操作的幂等重放时为真。

invoice_nostring
可为 null

开具后的发票号码。

invoice_statusstring

订单的增值税发票状态。none 表示尚未开具。

nonependingissuingissuedfailedcancelled
itemsobject[]
—
cancellableobject

eSIM 是否仍可取消及原因,请在调用 POST /v1/esims/{order_item_id}/cancel 前读取。此区块是明确回答,始终存在,不为 null。

allowedboolean
—
disclosed_atstring · date-time
可为 null

代码离开系统的时间(ISO-8601 UTC),无人查看时为 null。客户声称未收到代码却无法取消时,可据此核查。

reasonstring
可为 null

不可取消原因:code_disclosed(已发送或显示代码)、wrong_status(状态不允许)、expired(已过期)、not_supported(未声明取消能力)。allowed = true 时为 null,与 esim.not_cancellable 的 meta.reason 使用同一代码集。

code_disclosedwrong_statusexpirednot_supportednull
external_refstring
可为 null

您的订单引用(下单时发送的 external_ref),用于将 eSIM 对应到您的订单。未提供时为 null。

iccidstring
可为 null
—
idstring · uuid

eSIM ID,用于所有 /v1/esims/{id}/… 路径,也就是 webhook 中的 order_item_id。若只有 ICCID,请调用 GET /v1/esims?iccid=… 获取 id。

installobject
可为 null

安装此 eSIM 所需的全部信息。null 表示您未请求此信息(未传 include=lpa),并不表示 eSIM 尚无安装代码;后者会返回此对象且 lpa: null。

包含此对象的响应始终带有 Cache-Control: no-store。

android_urlstring
可为 null
—
apnstring
可为 null

设备无法自动获取配置时需输入的接入点名称(APN)。当前版本始终为 null,表示“未知”,而非“不需要”。

ios_urlstring
可为 null
—
lpastring
可为 null

eSIM 激活码,属于可销售的机密。仅凭此字符串即可在您的系统生成二维码。

matching_idstring
可为 null
—
qr_code_base64string
可为 null

二维码的 PNG data-URI。仅在详情端点请求 include=qr 时返回,列表绝不包含(每行约 11 KB,100 行约 1.1 MB);列表中请使用 lpa 自行生成二维码。

smdp_addressstring
可为 null
—
msisdnstring
可为 null
—
order_idstring · uuid
—
package_codestring
可为 null

目录中的套餐代码,用于将此 eSIM 对应回您的目录。仅当源套餐已从目录移除时为 null。

package_namestring

供人阅读、可能变化的显示名称。请勿用作对账键。

planobject
可为 null

此 eSIM 当前使用的套餐。

current_codestring
—
expires_atstring · date-time
可为 null
—
started_atstring · date-time
可为 null
—
smdp_statusstring
可为 null
—
statusstring
—
updated_atstring · date-time
—
usageobject
可为 null

eSIM 流量使用统计,从未查询过时 updated_at = null。

expires_atstring · date-time
可为 null
—
remaining_bytesinteger · int64
可为 null
—
sourcestring
可为 null
—
pollwebhook
total_bytesinteger · int64
可为 null
—
updated_atstring · date-time
可为 null
—
used_bytesinteger · int64
可为 null
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
money_settledboolean

订单资金是否已结算(无处理中退款)。false 表示暂时不能开票。

netobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
public_refstring
可为 null

简短易读的订单编号,提交支持工单时使用。

refundedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
statusstring
—
completedpending_providerprovider_failedcancelled
totalobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
okboolean
必填
—
true
201成功

成功

字段类型约束说明
dataobject
必填

合作伙伴订单。

created_atstring · date-time
—
external_refstring
可为 null
—
fulfillment_statusstring

实际交付情况,与 status 是独立维度。订单含 3 个 eSIM,其中 2 个交付、1 个失败时,仍为 status=completed,同时 fulfillment_status=partially_fulfilled 且 refunded_amount > 0。

fulfilledpartially_fulfilledunfulfilled
idstring · uuid

订单 ID(UUID)。

idempotent_replayboolean
可为 null

此请求为先前成功操作的幂等重放时为真。

invoice_nostring
可为 null

开具后的发票号码。

invoice_statusstring

订单的增值税发票状态。none 表示尚未开具。

nonependingissuingissuedfailedcancelled
itemsobject[]
—
cancellableobject

eSIM 是否仍可取消及原因,请在调用 POST /v1/esims/{order_item_id}/cancel 前读取。此区块是明确回答,始终存在,不为 null。

allowedboolean
—
disclosed_atstring · date-time
可为 null

代码离开系统的时间(ISO-8601 UTC),无人查看时为 null。客户声称未收到代码却无法取消时,可据此核查。

reasonstring
可为 null

不可取消原因:code_disclosed(已发送或显示代码)、wrong_status(状态不允许)、expired(已过期)、not_supported(未声明取消能力)。allowed = true 时为 null,与 esim.not_cancellable 的 meta.reason 使用同一代码集。

code_disclosedwrong_statusexpirednot_supportednull
external_refstring
可为 null

您的订单引用(下单时发送的 external_ref),用于将 eSIM 对应到您的订单。未提供时为 null。

iccidstring
可为 null
—
idstring · uuid

eSIM ID,用于所有 /v1/esims/{id}/… 路径,也就是 webhook 中的 order_item_id。若只有 ICCID,请调用 GET /v1/esims?iccid=… 获取 id。

installobject
可为 null

安装此 eSIM 所需的全部信息。null 表示您未请求此信息(未传 include=lpa),并不表示 eSIM 尚无安装代码;后者会返回此对象且 lpa: null。

包含此对象的响应始终带有 Cache-Control: no-store。

android_urlstring
可为 null
—
apnstring
可为 null

设备无法自动获取配置时需输入的接入点名称(APN)。当前版本始终为 null,表示“未知”,而非“不需要”。

ios_urlstring
可为 null
—
lpastring
可为 null

eSIM 激活码,属于可销售的机密。仅凭此字符串即可在您的系统生成二维码。

matching_idstring
可为 null
—
qr_code_base64string
可为 null

二维码的 PNG data-URI。仅在详情端点请求 include=qr 时返回,列表绝不包含(每行约 11 KB,100 行约 1.1 MB);列表中请使用 lpa 自行生成二维码。

smdp_addressstring
可为 null
—
msisdnstring
可为 null
—
order_idstring · uuid
—
package_codestring
可为 null

目录中的套餐代码,用于将此 eSIM 对应回您的目录。仅当源套餐已从目录移除时为 null。

package_namestring

供人阅读、可能变化的显示名称。请勿用作对账键。

planobject
可为 null

此 eSIM 当前使用的套餐。

current_codestring
—
expires_atstring · date-time
可为 null
—
started_atstring · date-time
可为 null
—
smdp_statusstring
可为 null
—
statusstring
—
updated_atstring · date-time
—
usageobject
可为 null

eSIM 流量使用统计,从未查询过时 updated_at = null。

expires_atstring · date-time
可为 null
—
remaining_bytesinteger · int64
可为 null
—
sourcestring
可为 null
—
pollwebhook
total_bytesinteger · int64
可为 null
—
updated_atstring · date-time
可为 null
—
used_bytesinteger · int64
可为 null
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
money_settledboolean

订单资金是否已结算(无处理中退款)。false 表示暂时不能开票。

netobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
public_refstring
可为 null

简短易读的订单编号,提交支持工单时使用。

refundedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
statusstring
—
completedpending_providerprovider_failedcancelled
totalobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failedinternal.invalid_filter
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
402
wallet.insufficient_balance
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
partner.package_not_visible
409
esim.out_of_stockidempotency.conflict
422
invoice.buyer_invalid
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="POST"
REQ_PATH="/v1/orders"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"external_ref":"po-1001","include":["lpa"],"invoice_buyer":{"address":"<address>","email":"<email>","full_name":"<full_name>","legal_name":"<legal_name>","tax_code":"TKE-VN-30D-X3K9F"},"items":[{"package_code":"TKE-VN-30D-X3K9F","quantity":2}]}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "created_at": "2026-07-11T08:12:30Z",
    "external_ref": "po-1001",
    "fulfillment_status": "fulfilled",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "idempotent_replay": true,
    "invoice_no": "<invoice_no>",
    "invoice_status": "none",
    "items": [
      {
        "cancellable": {
          "allowed": true,
          "disclosed_at": "2026-07-11T08:12:30Z",
          "reason": "code_disclosed"
        },
        "external_ref": "po-1001",
        "iccid": "8984012345678901234",
        "id": "018f2b00-0000-7000-8000-00000000009a",
        "install": {
          "android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
          "apn": "<apn>",
          "ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
          "lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
          "matching_id": "MATCH-ABC123",
          "qr_code_base64": "<PNG base64 — đã rút gọn>",
          "smdp_address": "smdp.example.com"
        },
        "msisdn": "+84900000000",
        "order_id": "018f2b00-0000-7000-8000-00000000009a",
        "package_code": "TKE-VN-30D-X3K9F",
        "package_name": "Tên gói hiển thị",
        "plan": {
          "current_code": "TKE-VN-30D-X3K9F",
          "expires_at": "2026-08-10T00:00:00Z",
          "started_at": "2026-07-11T08:12:30Z"
        },
        "smdp_status": "released",
        "status": "delivered",
        "updated_at": "2026-07-11T09:03:11Z",
        "usage": {
          "expires_at": "2026-08-10T00:00:00Z",
          "remaining_bytes": 5368709120,
          "source": "poll",
          "total_bytes": 5368709120,
          "updated_at": "2026-07-11T09:03:11Z",
          "used_bytes": 5368709120
        }
      }
    ],
    "mode": "live",
    "money_settled": true,
    "net": {
      "amount": 273000,
      "currency": "VND"
    },
    "public_ref": "TKE-DH-2A4C7Q",
    "refunded": {
      "amount": 273000,
      "currency": "VND"
    },
    "status": "completed",
    "total": {
      "amount": 273000,
      "currency": "VND"
    }
  },
  "ok": true
}

请求体示例

json
{
  "external_ref": "po-1001",
  "include": [
    "lpa"
  ],
  "invoice_buyer": {
    "address": "<address>",
    "email": "<email>",
    "full_name": "<full_name>",
    "legal_name": "<legal_name>",
    "tax_code": "TKE-VN-30D-X3K9F"
  },
  "items": [
    {
      "package_code": "TKE-VN-30D-X3K9F",
      "quantity": 2
    }
  ]
}
GET/v1/orders/{id}

订单详情及 eSIM

scope orders:readget_orders__id_

所需权限范围: orders:read.

路径参数 (1)

idstring必填

订单 ID(UUID)。

查询参数 (1)

includestring选填

用逗号分隔额外区块:lpa 返回 install,qr 额外返回 install.qr_code_base64(仅详情端点)。返回代码即披露,响应中所有 eSIM 将永久不可取消(cancellable.allowed = false,reason = code_disclosed)。立即交付客户时再请求;提前订购时省略可保留取消权。未知值返回 internal.invalid_filter(400,field: "include")。

响应

200成功

成功

字段类型约束说明
dataobject
必填

合作伙伴订单。

created_atstring · date-time
—
external_refstring
可为 null
—
fulfillment_statusstring

实际交付情况,与 status 是独立维度。订单含 3 个 eSIM,其中 2 个交付、1 个失败时,仍为 status=completed,同时 fulfillment_status=partially_fulfilled 且 refunded_amount > 0。

fulfilledpartially_fulfilledunfulfilled
idstring · uuid

订单 ID(UUID)。

idempotent_replayboolean
可为 null

此请求为先前成功操作的幂等重放时为真。

invoice_nostring
可为 null

开具后的发票号码。

invoice_statusstring

订单的增值税发票状态。none 表示尚未开具。

nonependingissuingissuedfailedcancelled
itemsobject[]
—
cancellableobject

eSIM 是否仍可取消及原因,请在调用 POST /v1/esims/{order_item_id}/cancel 前读取。此区块是明确回答,始终存在,不为 null。

allowedboolean
—
disclosed_atstring · date-time
可为 null

代码离开系统的时间(ISO-8601 UTC),无人查看时为 null。客户声称未收到代码却无法取消时,可据此核查。

reasonstring
可为 null

不可取消原因:code_disclosed(已发送或显示代码)、wrong_status(状态不允许)、expired(已过期)、not_supported(未声明取消能力)。allowed = true 时为 null,与 esim.not_cancellable 的 meta.reason 使用同一代码集。

code_disclosedwrong_statusexpirednot_supportednull
external_refstring
可为 null

您的订单引用(下单时发送的 external_ref),用于将 eSIM 对应到您的订单。未提供时为 null。

iccidstring
可为 null
—
idstring · uuid

eSIM ID,用于所有 /v1/esims/{id}/… 路径,也就是 webhook 中的 order_item_id。若只有 ICCID,请调用 GET /v1/esims?iccid=… 获取 id。

installobject
可为 null

安装此 eSIM 所需的全部信息。null 表示您未请求此信息(未传 include=lpa),并不表示 eSIM 尚无安装代码;后者会返回此对象且 lpa: null。

包含此对象的响应始终带有 Cache-Control: no-store。

android_urlstring
可为 null
—
apnstring
可为 null

设备无法自动获取配置时需输入的接入点名称(APN)。当前版本始终为 null,表示“未知”,而非“不需要”。

ios_urlstring
可为 null
—
lpastring
可为 null

eSIM 激活码,属于可销售的机密。仅凭此字符串即可在您的系统生成二维码。

matching_idstring
可为 null
—
qr_code_base64string
可为 null

二维码的 PNG data-URI。仅在详情端点请求 include=qr 时返回,列表绝不包含(每行约 11 KB,100 行约 1.1 MB);列表中请使用 lpa 自行生成二维码。

smdp_addressstring
可为 null
—
msisdnstring
可为 null
—
order_idstring · uuid
—
package_codestring
可为 null

目录中的套餐代码,用于将此 eSIM 对应回您的目录。仅当源套餐已从目录移除时为 null。

package_namestring

供人阅读、可能变化的显示名称。请勿用作对账键。

planobject
可为 null

此 eSIM 当前使用的套餐。

current_codestring
—
expires_atstring · date-time
可为 null
—
started_atstring · date-time
可为 null
—
smdp_statusstring
可为 null
—
statusstring
—
updated_atstring · date-time
—
usageobject
可为 null

eSIM 流量使用统计,从未查询过时 updated_at = null。

expires_atstring · date-time
可为 null
—
remaining_bytesinteger · int64
可为 null
—
sourcestring
可为 null
—
pollwebhook
total_bytesinteger · int64
可为 null
—
updated_atstring · date-time
可为 null
—
used_bytesinteger · int64
可为 null
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
money_settledboolean

订单资金是否已结算(无处理中退款)。false 表示暂时不能开票。

netobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
public_refstring
可为 null

简短易读的订单编号,提交支持工单时使用。

refundedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
statusstring
—
completedpending_providerprovider_failedcancelled
totalobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failedinternal.invalid_filter
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
internal.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="GET"
REQ_PATH="/v1/orders/$ID"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "created_at": "2026-07-11T08:12:30Z",
    "external_ref": "po-1001",
    "fulfillment_status": "fulfilled",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "idempotent_replay": true,
    "invoice_no": "<invoice_no>",
    "invoice_status": "none",
    "items": [
      {
        "cancellable": {
          "allowed": true,
          "disclosed_at": "2026-07-11T08:12:30Z",
          "reason": "code_disclosed"
        },
        "external_ref": "po-1001",
        "iccid": "8984012345678901234",
        "id": "018f2b00-0000-7000-8000-00000000009a",
        "install": {
          "android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
          "apn": "<apn>",
          "ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
          "lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
          "matching_id": "MATCH-ABC123",
          "qr_code_base64": "<PNG base64 — đã rút gọn>",
          "smdp_address": "smdp.example.com"
        },
        "msisdn": "+84900000000",
        "order_id": "018f2b00-0000-7000-8000-00000000009a",
        "package_code": "TKE-VN-30D-X3K9F",
        "package_name": "Tên gói hiển thị",
        "plan": {
          "current_code": "TKE-VN-30D-X3K9F",
          "expires_at": "2026-08-10T00:00:00Z",
          "started_at": "2026-07-11T08:12:30Z"
        },
        "smdp_status": "released",
        "status": "delivered",
        "updated_at": "2026-07-11T09:03:11Z",
        "usage": {
          "expires_at": "2026-08-10T00:00:00Z",
          "remaining_bytes": 5368709120,
          "source": "poll",
          "total_bytes": 5368709120,
          "updated_at": "2026-07-11T09:03:11Z",
          "used_bytes": 5368709120
        }
      }
    ],
    "mode": "live",
    "money_settled": true,
    "net": {
      "amount": 273000,
      "currency": "VND"
    },
    "public_ref": "TKE-DH-2A4C7Q",
    "refunded": {
      "amount": 273000,
      "currency": "VND"
    },
    "status": "completed",
    "total": {
      "amount": 273000,
      "currency": "VND"
    }
  },
  "ok": true
}
POST/v1/orders/{id}/resend

重新发送订单邮件/二维码

scope orders:writepost_orders__id__resend

所需权限范围: orders:write.

路径参数 (1)

idstring必填

订单 ID(UUID)。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
idstring · uuid

刚刚重新发送的订单 ID。

modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
resent_atstring · date-time
—
resent_tostring

部分隐藏的收件地址,合作伙伴接口不会重新返回客户的完整邮箱。

okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
409
order.not_deliverable
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="POST"
REQ_PATH="/v1/orders/$ID/resend"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "mode": "live",
    "resent_at": "2026-07-11T08:12:30Z",
    "resent_to": "ab***@x.com"
  },
  "ok": true
}
POST/v1/orders/bulk

提交多行批量订单(每行一个订单)

scope orders:write必须提供 Idempotency-Keypost_orders_bulk

所需权限范围: orders:write.

提交多行批次,每行独立生成一个订单,执行与 POST /v1/orders 相同的 quote→commit。

部分成功:失败行不阻止其他行,只扣成功行款项。缺货、余额不足、套餐不可售、触发防滥用限制等业务错误位于 lines[].error,不影响批次整体 HTTP 状态。中途余额不足仍尝试后续行,因为较便宜的套餐可能仍可购买。

状态始终为 200:结果是逐行混合结果而非单一新资源,故不是 201;批次在请求内处理完成,不使用 202 加轮询。

相同 Idempotency-Key 加相同请求体再次调用,将加载旧批次、原样返回已完成行,仅继续处理 pending 行,不重复扣款。未执行任何行时附带 Idempotent-Replayed: true。同密钥但请求体不同则为 idempotency.conflict。

同一组织在 10 分钟内提交内容相同的批次,即使幂等键不同,也视为误点重复提交:返回旧批次并带 Idempotent-Replayed: true,不再扣款。若确需为另一客户购买相同商品,请修改 external_ref;它属于签名内容,可区分批次并用于后续对账。全部失败、未产生任何订单的批次不会受此限制,超过 10 分钟也可正常重购。

行级 external_ref 原样返回于 lines[].external_ref,批次级参考编号返回于响应顶部。

响应不包含 LPA/QR,请按各 order_id 从 GET /v1/orders/{order_id} 获取。

请求头 (1)

Idempotency-Keystring必填

客户端生成的字符串:相同密钥和请求体只执行一次,重试返回原结果。范围为 api_key_id(§11),不同密钥属于不同命令。

请求体必填application/json

字段类型约束说明
external_refstring
可为 null

整个批次的参考编号,会在批次响应中返回。

itemsobject[]
必填

每个条目创建一个独立订单。行数上限可配置(默认 100),超出返回 internal.limit_exceeded(422)。

external_refstring
可为 null

仅此行的参考编号,会在该行结果中原样返回。

package_codestring
必填

您目录中的套餐代码,即 public_sku。每个套餐的代码不可变,更换底层供应商时也不变,因此可安全用作对账键。示例仅格式正确,无法实际调用;请从 GET /v1/catalog/packages 获取真实代码。

quantityinteger
必填
—

响应

200成功

成功

字段类型约束说明
dataobject
必填

批量订单结果。部分成功:失败行不阻止其他行,仅对 done 行扣款。不含 LPA/QR,请按各 order_id 通过 GET /v1/orders/{id} 获取。

created_atstring · date-time
—
external_refstring
可为 null
—
failed_linesinteger
—
idstring · uuid
—
itemsobject[]
—
chargedobject
可为 null
—
errorobject
可为 null

实际的 domain.reason 错误代码,例如 wallet.insufficient_balance、esim.out_of_stock、order.package_not_allowed、wallet.velocity_exceeded。

codestring
—
messagestring
—
external_refstring
可为 null
—
line_nointeger

从 1 开始,与提交顺序完全一致。

order_idstring · uuid
可为 null
—
package_codestring
—
quantityinteger
—
statusstring
—
pendingdonefailed
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
statusstring

pending 表示批次中仍有未执行行(中途被中断),请使用相同 Idempotency-Key 再调用以完成剩余行。

pendingcompletedpartialfailed
succeeded_linesinteger
—
total_chargedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
total_linesinteger
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
partner.package_not_visible
409
idempotency.conflict
422
internal.limit_exceeded
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="POST"
REQ_PATH="/v1/orders/bulk"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"external_ref":"batch-2026-001","items":[{"external_ref":"po-1001","package_code":"TKE-VN-30D-X3K9F","quantity":5}]}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "created_at": "2026-07-11T08:12:30Z",
    "external_ref": "batch-2026-001",
    "failed_lines": 1,
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "items": [
      {
        "charged": null,
        "error": {
          "code": "TKE-VN-30D-X3K9F",
          "message": "<message>"
        },
        "external_ref": "po-1001",
        "line_no": 1,
        "order_id": "018f2b00-0000-7000-8000-00000000009a",
        "package_code": "TKE-VN-30D-X3K9F",
        "quantity": 2,
        "status": "pending"
      }
    ],
    "mode": "live",
    "status": "pending",
    "succeeded_lines": 1,
    "total_charged": {
      "amount": 273000,
      "currency": "VND"
    },
    "total_lines": 1
  },
  "ok": true
}

请求体示例

json
{
  "external_ref": "batch-2026-001",
  "items": [
    {
      "external_ref": "po-1001",
      "package_code": "TKE-VN-30D-X3K9F",
      "quantity": 5
    }
  ]
}
GET/v1/orders/bulk/{id}

批量订单结果

scope orders:readget_orders_bulk__id_

所需权限范围: orders:read.

重新读取已提交批次的逐行结果,可在原始响应丢失时恢复,无须重发请求体。其他组织或其他环境(正式/测试)的批次返回 404。

路径参数 (1)

idstring必填

POST /v1/orders/bulk 返回的批次 ID(UUID)。

响应

200成功

成功

字段类型约束说明
dataobject
必填

批量订单结果。部分成功:失败行不阻止其他行,仅对 done 行扣款。不含 LPA/QR,请按各 order_id 通过 GET /v1/orders/{id} 获取。

created_atstring · date-time
—
external_refstring
可为 null
—
failed_linesinteger
—
idstring · uuid
—
itemsobject[]
—
chargedobject
可为 null
—
errorobject
可为 null

实际的 domain.reason 错误代码,例如 wallet.insufficient_balance、esim.out_of_stock、order.package_not_allowed、wallet.velocity_exceeded。

codestring
—
messagestring
—
external_refstring
可为 null
—
line_nointeger

从 1 开始,与提交顺序完全一致。

order_idstring · uuid
可为 null
—
package_codestring
—
quantityinteger
—
statusstring
—
pendingdonefailed
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
statusstring

pending 表示批次中仍有未执行行(中途被中断),请使用相同 Idempotency-Key 再调用以完成剩余行。

pendingcompletedpartialfailed
succeeded_linesinteger
—
total_chargedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
total_linesinteger
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
internal.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="GET"
REQ_PATH="/v1/orders/bulk/$ID"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "created_at": "2026-07-11T08:12:30Z",
    "external_ref": "batch-2026-001",
    "failed_lines": 1,
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "items": [
      {
        "charged": null,
        "error": {
          "code": "TKE-VN-30D-X3K9F",
          "message": "<message>"
        },
        "external_ref": "po-1001",
        "line_no": 1,
        "order_id": "018f2b00-0000-7000-8000-00000000009a",
        "package_code": "TKE-VN-30D-X3K9F",
        "quantity": 2,
        "status": "pending"
      }
    ],
    "mode": "live",
    "status": "pending",
    "succeeded_lines": 1,
    "total_charged": {
      "amount": 273000,
      "currency": "VND"
    },
    "total_lines": 1
  },
  "ok": true
}

eSIM

eSIM 记录、用量、加购及取消

GET/v1/esims

列出 eSIM(主动查询式对账)

scope esims:readget_esims

所需权限范围: esims:read.

查询参数 (8)

page_sizeinteger选填默认值 50min 1max 200

每页记录数,默认 50,上限 200;超过上限时限制为 200,不报错。

statusstring选填
允许的值:pendingavailablereservedsolddeliveredin_useused_upexpiredsuspendedcancelledprovider_failed

按 esim_status 筛选。列表之外的值返回 internal.invalid_filter(400),而非空列表,以免将拼写错误(如 cancelled 少写一个 l 的 canceled)误认为该客户没有此状态的 eSIM。

order_idstring · uuid选填

仅查询同一订单的 eSIM。

iccidstring选填

按 ICCID 筛选(字符串,精确匹配)。

external_refstring选填

带有您的订单引用(下单时发送的 external_ref,精确匹配)的所有订单 eSIM。

updated_sincestring · date-time选填

ISO-8601 UTC 时间。按升序返回所有满足 updated_at >= updated_since 的记录,是标准主动查询式对账路径(§8.5);即使遗漏 webhook,也可从状态重建。格式错误返回 internal.invalid_filter(400)。

cursorstring选填

下一页游标,请原样传回上一页的 next_cursor。畸形游标不会报错,而会从列表开头读取,以兼容游标编码变更。请确认新游标与刚发送的值不同,避免无限循环读取第一页。

includestring选填

用逗号分隔额外区块:lpa 返回 install,qr 额外返回 install.qr_code_base64(仅详情端点)。返回代码即披露,响应中所有 eSIM 将永久不可取消(cancellable.allowed = false,reason = code_disclosed)。立即交付客户时再请求;提前订购时省略可保留取消权。未知值返回 internal.invalid_filter(400,field: "include")。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
itemsobject[]
—
cancellableobject

eSIM 是否仍可取消及原因,请在调用 POST /v1/esims/{order_item_id}/cancel 前读取。此区块是明确回答,始终存在,不为 null。

allowedboolean
—
disclosed_atstring · date-time
可为 null

代码离开系统的时间(ISO-8601 UTC),无人查看时为 null。客户声称未收到代码却无法取消时,可据此核查。

reasonstring
可为 null

不可取消原因:code_disclosed(已发送或显示代码)、wrong_status(状态不允许)、expired(已过期)、not_supported(未声明取消能力)。allowed = true 时为 null,与 esim.not_cancellable 的 meta.reason 使用同一代码集。

code_disclosedwrong_statusexpirednot_supportednull
external_refstring
可为 null

您的订单引用(下单时发送的 external_ref),用于将 eSIM 对应到您的订单。未提供时为 null。

iccidstring
可为 null
—
idstring · uuid

eSIM ID,用于所有 /v1/esims/{id}/… 路径,也就是 webhook 中的 order_item_id。若只有 ICCID,请调用 GET /v1/esims?iccid=… 获取 id。

installobject
可为 null

安装此 eSIM 所需的全部信息。null 表示您未请求此信息(未传 include=lpa),并不表示 eSIM 尚无安装代码;后者会返回此对象且 lpa: null。

包含此对象的响应始终带有 Cache-Control: no-store。

android_urlstring
可为 null
—
apnstring
可为 null

设备无法自动获取配置时需输入的接入点名称(APN)。当前版本始终为 null,表示“未知”,而非“不需要”。

ios_urlstring
可为 null
—
lpastring
可为 null

eSIM 激活码,属于可销售的机密。仅凭此字符串即可在您的系统生成二维码。

matching_idstring
可为 null
—
qr_code_base64string
可为 null

二维码的 PNG data-URI。仅在详情端点请求 include=qr 时返回,列表绝不包含(每行约 11 KB,100 行约 1.1 MB);列表中请使用 lpa 自行生成二维码。

smdp_addressstring
可为 null
—
msisdnstring
可为 null
—
order_idstring · uuid
—
package_codestring
可为 null

目录中的套餐代码,用于将此 eSIM 对应回您的目录。仅当源套餐已从目录移除时为 null。

package_namestring

供人阅读、可能变化的显示名称。请勿用作对账键。

planobject
可为 null

此 eSIM 当前使用的套餐。

current_codestring
—
expires_atstring · date-time
可为 null
—
started_atstring · date-time
可为 null
—
smdp_statusstring
可为 null
—
statusstring
—
updated_atstring · date-time
—
usageobject
可为 null

eSIM 流量使用统计,从未查询过时 updated_at = null。

expires_atstring · date-time
可为 null
—
remaining_bytesinteger · int64
可为 null
—
sourcestring
可为 null
—
pollwebhook
total_bytesinteger · int64
可为 null
—
updated_atstring · date-time
可为 null
—
used_bytesinteger · int64
可为 null
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_cursorstring
可为 null

获取下一页时请原样传回。null 是唯一的结束信号,即使当前页少于 page_size 条,也可能仍有后续页面。

page_sizeinteger
可为 null

服务器用于本页的最大记录数,已应用上限,并非 items 中的实际元素数量。

totalinteger · int64
可为 null

符合筛选条件的记录数量。统计成本过高时为 null,请勿据此判断是否结束,应以 next_cursor 为准。

warningsobject[]

列表呈现方式的原因;无异常时为空。封闭代码集:filtered_by_key_package_filters、filtered_by_provider_scope、no_price_for_org、price_filter_removed_rows、provider_disabled、capability_missing,分别代表密钥限制、组织供应源范围、未定价、价格筛选、供应商停用、未声明功能。count 为涉及行数,无法量化时为 null。

codestring
—
filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing
countinteger · int64
可为 null
—
messagestring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failedinternal.invalid_filter
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="GET"
REQ_PATH="/v1/esims"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "items": [
      {
        "cancellable": {
          "allowed": true,
          "disclosed_at": "2026-07-11T08:12:30Z",
          "reason": "code_disclosed"
        },
        "external_ref": "po-1001",
        "iccid": "8984012345678901234",
        "id": "018f2b00-0000-7000-8000-00000000009a",
        "install": {
          "android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
          "apn": "<apn>",
          "ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
          "lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
          "matching_id": "MATCH-ABC123",
          "qr_code_base64": "<PNG base64 — đã rút gọn>",
          "smdp_address": "smdp.example.com"
        },
        "msisdn": "+84900000000",
        "order_id": "018f2b00-0000-7000-8000-00000000009a",
        "package_code": "TKE-VN-30D-X3K9F",
        "package_name": "Tên gói hiển thị",
        "plan": {
          "current_code": "TKE-VN-30D-X3K9F",
          "expires_at": "2026-08-10T00:00:00Z",
          "started_at": "2026-07-11T08:12:30Z"
        },
        "smdp_status": "released",
        "status": "delivered",
        "updated_at": "2026-07-11T09:03:11Z",
        "usage": {
          "expires_at": "2026-08-10T00:00:00Z",
          "remaining_bytes": 5368709120,
          "source": "poll",
          "total_bytes": 5368709120,
          "updated_at": "2026-07-11T09:03:11Z",
          "used_bytes": 5368709120
        }
      }
    ],
    "mode": "live",
    "next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
    "page_size": 50,
    "total": 128,
    "warnings": []
  },
  "ok": true
}
GET/v1/esims/{id}

获取单个 eSIM

scope esims:readget_esims__id_

所需权限范围: esims:read.

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

查询参数 (1)

includestring选填

用逗号分隔额外区块:lpa 返回 install,qr 额外返回 install.qr_code_base64(仅详情端点)。返回代码即披露,响应中所有 eSIM 将永久不可取消(cancellable.allowed = false,reason = code_disclosed)。立即交付客户时再请求;提前订购时省略可保留取消权。未知值返回 internal.invalid_filter(400,field: "include")。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
cancellableobject

eSIM 是否仍可取消及原因,请在调用 POST /v1/esims/{order_item_id}/cancel 前读取。此区块是明确回答,始终存在,不为 null。

allowedboolean
—
disclosed_atstring · date-time
可为 null

代码离开系统的时间(ISO-8601 UTC),无人查看时为 null。客户声称未收到代码却无法取消时,可据此核查。

reasonstring
可为 null

不可取消原因:code_disclosed(已发送或显示代码)、wrong_status(状态不允许)、expired(已过期)、not_supported(未声明取消能力)。allowed = true 时为 null,与 esim.not_cancellable 的 meta.reason 使用同一代码集。

code_disclosedwrong_statusexpirednot_supportednull
external_refstring
可为 null

您的订单引用(下单时发送的 external_ref),用于将 eSIM 对应到您的订单。未提供时为 null。

iccidstring
可为 null
—
idstring · uuid

eSIM ID,用于所有 /v1/esims/{id}/… 路径,也就是 webhook 中的 order_item_id。若只有 ICCID,请调用 GET /v1/esims?iccid=… 获取 id。

installobject
可为 null

安装此 eSIM 所需的全部信息。null 表示您未请求此信息(未传 include=lpa),并不表示 eSIM 尚无安装代码;后者会返回此对象且 lpa: null。

包含此对象的响应始终带有 Cache-Control: no-store。

android_urlstring
可为 null
—
apnstring
可为 null

设备无法自动获取配置时需输入的接入点名称(APN)。当前版本始终为 null,表示“未知”,而非“不需要”。

ios_urlstring
可为 null
—
lpastring
可为 null

eSIM 激活码,属于可销售的机密。仅凭此字符串即可在您的系统生成二维码。

matching_idstring
可为 null
—
qr_code_base64string
可为 null

二维码的 PNG data-URI。仅在详情端点请求 include=qr 时返回,列表绝不包含(每行约 11 KB,100 行约 1.1 MB);列表中请使用 lpa 自行生成二维码。

smdp_addressstring
可为 null
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
msisdnstring
可为 null
—
order_idstring · uuid
—
package_codestring
可为 null

目录中的套餐代码,用于将此 eSIM 对应回您的目录。仅当源套餐已从目录移除时为 null。

package_namestring

供人阅读、可能变化的显示名称。请勿用作对账键。

planobject
可为 null

此 eSIM 当前使用的套餐。

current_codestring
—
expires_atstring · date-time
可为 null
—
started_atstring · date-time
可为 null
—
smdp_statusstring
可为 null
—
statusstring
—
updated_atstring · date-time
—
usageobject
可为 null

eSIM 流量使用统计,从未查询过时 updated_at = null。

expires_atstring · date-time
可为 null
—
remaining_bytesinteger · int64
可为 null
—
sourcestring
可为 null
—
pollwebhook
total_bytesinteger · int64
可为 null
—
updated_atstring · date-time
可为 null
—
used_bytesinteger · int64
可为 null
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failedinternal.invalid_filter
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
internal.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="GET"
REQ_PATH="/v1/esims/$ID"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "cancellable": {
      "allowed": true,
      "disclosed_at": "2026-07-11T08:12:30Z",
      "reason": "code_disclosed"
    },
    "external_ref": "po-1001",
    "iccid": "8984012345678901234",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "install": {
      "android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
      "apn": "<apn>",
      "ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
      "lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
      "matching_id": "MATCH-ABC123",
      "qr_code_base64": "<PNG base64 — đã rút gọn>",
      "smdp_address": "smdp.example.com"
    },
    "mode": "live",
    "msisdn": "+84900000000",
    "order_id": "018f2b00-0000-7000-8000-00000000009a",
    "package_code": "TKE-VN-30D-X3K9F",
    "package_name": "Tên gói hiển thị",
    "plan": {
      "current_code": "TKE-VN-30D-X3K9F",
      "expires_at": "2026-08-10T00:00:00Z",
      "started_at": "2026-07-11T08:12:30Z"
    },
    "smdp_status": "released",
    "status": "delivered",
    "updated_at": "2026-07-11T09:03:11Z",
    "usage": {
      "expires_at": "2026-08-10T00:00:00Z",
      "remaining_bytes": 5368709120,
      "source": "poll",
      "total_bytes": 5368709120,
      "updated_at": "2026-07-11T09:03:11Z",
      "used_bytes": 5368709120
    }
  },
  "ok": true
}
POST/v1/esims/{id}/cancel

取消未使用的 eSIM

scope esims:write必须提供 Idempotency-Keypost_esims__id__cancel

所需权限范围: esims:write.

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

请求头 (1)

Idempotency-Keystring必填

客户端生成的字符串:相同密钥和请求体只执行一次,重试返回原结果。范围为 api_key_id(§11),不同密钥属于不同命令。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
cancelled_atstring · date-time
—
esim_idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
refund_suggestedboolean

true 表示退款申请已排队等待人工批准,资金尚未转移。不要将 refunded.amount = 0 解读为“不退款”。

refundedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
statusstring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
409
esim.not_cancellableidempotency.conflict
422
capability.not_supported
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="POST"
REQ_PATH="/v1/esims/$ID/cancel"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Idempotency-Key: $(uuidgen)"

响应示例

json
{
  "data": {
    "cancelled_at": "2026-07-11T08:12:30Z",
    "esim_id": "018f2b00-0000-7000-8000-000000000000",
    "mode": "live",
    "refund_suggested": true,
    "refunded": {
      "amount": 273000,
      "currency": "VND"
    },
    "status": "cancelled"
  },
  "ok": true
}
POST/v1/esims/{id}/change-plan

为 eSIM 加购

scope esims:write必须提供 Idempotency-Keypost_esims__id__change-plan

所需权限范围: esims:write.

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

请求头 (1)

Idempotency-Keystring必填

客户端生成的字符串:相同密钥和请求体只执行一次,重试返回原结果。范围为 api_key_id(§11),不同密钥属于不同命令。

请求体必填application/json

字段类型约束说明
package_codestring
必填

您目录中的套餐代码,即 public_sku。每个套餐的代码不可变,更换底层供应商时也不变,因此可安全用作对账键。示例仅格式正确,无法实际调用;请从 GET /v1/catalog/packages 获取真实代码。

响应

200成功

成功

字段类型约束说明
dataobject
必填

eSIM 更换套餐的结果。

chargedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
current_planobject
—
codestring
—
expires_atstring · date-time
可为 null
—
started_atstring · date-time
可为 null
—
esim_idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
order_idstring · uuid
—
previous_planobject
可为 null
—
cancelled_atstring · date-time
可为 null
—
codestring
—
remaining_bytes_forfeitedinteger · int64
可为 null
—
warningstring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
402
wallet.insufficient_balance
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
partner.package_not_visible
409
esim.topup_not_supportedesim.topup_provider_mismatchesim.not_eligibleidempotency.conflict
422
capability.not_supported
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="POST"
REQ_PATH="/v1/esims/$ID/change-plan"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"package_code":"TKE-VN-7D-P4M2Q"}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "charged": {
      "amount": 273000,
      "currency": "VND"
    },
    "current_plan": {
      "code": "TKE-VN-30D-X3K9F",
      "expires_at": "2026-08-10T00:00:00Z",
      "started_at": "2026-07-11T08:12:30Z"
    },
    "esim_id": "018f2b00-0000-7000-8000-000000000000",
    "mode": "live",
    "order_id": "018f2b00-0000-7000-8000-00000000009a",
    "previous_plan": {
      "cancelled_at": "2026-07-11T08:12:30Z",
      "code": "TKE-VN-30D-X3K9F",
      "remaining_bytes_forfeited": 2147483648
    },
    "warning": "Dung lượng còn lại của gói cũ KHÔNG được cộng dồn."
  },
  "ok": true
}

请求体示例

json
{
  "package_code": "TKE-VN-7D-P4M2Q"
}
GET/v1/esims/{id}/plan-options

此 eSIM 可用的加购套餐

scope esims:readget_esims__id__plan-options

所需权限范围: esims:read.

返回仅适用于此 eSIM 的可追加套餐。系统根据 id 确认所属供应商,只返回该供应商的套餐。/v1 不暴露 provider_id,此接口代为筛选,从结构上杜绝误选其他供应商的套餐。直接向 POST /v1/esims/{id}/change-plan 提交不在此列表中的套餐代码将返回 409 esim.topup_provider_mismatch。

从未关联供应商的 eSIM(纯导入或缺少来源信息)返回空列表(total: 0),这是正常结果而非错误。

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

查询参数 (2)

page_sizeinteger选填默认值 50min 1max 200

每页记录数,默认 50,上限 200;超过上限时限制为 200,不报错。

cursorstring选填

下一页游标,请原样传回上一页的 next_cursor。畸形游标不会报错,而会从列表开头读取,以兼容游标编码变更。请确认新游标与刚发送的值不同,避免无限循环读取第一页。

响应

200成功

成功

字段类型约束说明
dataobject
必填

可为此 eSIM 加购的套餐,已按当前供应商筛选。每项均为完整 Package,结构与目录相同。policy 是当前供应商政策,null 表示尚未核实,不能理解为“不会取消任何套餐”。

itemsobject[]
—
capabilitiesobject

套餐售后能力取自套餐实际声明,不根据供应商类型推断。未声明时所有标志为 false,避免承诺必然返回 422 capability.not_supported 的操作。

cancelobject
—
restrictionstring
可为 null

code_not_disclosed 表示仅在无人查看过激活码时可取消(包括未发送客户、未通过后台或 ?include=lpa 读取)。这是真实取消条件,与系统无法判断的安装状态无关。旧名称 unused_only 会造成错误承诺。

code_not_disclosednull
supportedboolean
—
plan_changeobject
—
policyobject
可为 null

此供应商追加新套餐时的处理方式。null 表示套餐无法追加,或尚未确认供应商政策,不能据此推断;全部字段为 false 的对象则表示保证不会取消任何套餐,两者含义不同。

……

还有更深层字段,请查看 JSON 示例。

supportedboolean
—
usage_checkobject
—
supportedboolean
—
codestring

您目录中的套餐代码,即 public_sku。每个套餐的代码不可变,更换底层供应商时也不变,因此可安全用作对账键。示例仅格式正确,无法实际调用;请从 GET /v1/catalog/packages 获取真实代码。

coverageobject

套餐可用地区。

countriesstring[]

ISO-3166 alpha-2 国家代码。全球套餐不逐一列出 200 个国家;全球套餐及未声明覆盖范围的套餐返回空数组。

country_countinteger

套餐覆盖的国家数量,可据此排序或筛选多国套餐,无须获取全部数据后自行统计数组。

groupstring

覆盖范围为国家列表(country)、地区(region)或全球(global)。开放枚举,必须忽略未知值。

regionstring
可为 null

始终为 null:地区关联国家而非套餐,填值将属于推断。仍可通过 ?region= 筛选。

dataobject

套餐流量额度,所有数值均以字节表示,而非 MB/GB,以避免重复舍入。

daily_bytesinteger · int64
可为 null

每日流量额度,单位为字节。fixed 或 unlimited 套餐为 null。

labelstring

由所有界面共用的函数生成的可读标签。

modelstring

流量计算方式:daily(每日额度)、fixed(整个有效期总量)或 unlimited。此枚举可扩展,客户端必须忽略未知值。

dailyfixedunlimited
resetobject
可为 null

每日额度重置时间。深夜购买时会影响首日可用时间,属于销售信息。null 表示未声明。

atstring
可为 null

按 timezone 所在时区表示的重置时间(00:00、00:00:01)。

notestring
可为 null
—
timezonestring
可为 null

重置时点的时区(UTC+8、UTC+7)。

total_bytesinteger · int64
可为 null

整个周期总流量(字节)。daily/unlimited 套餐为 null:每日额度乘天数并非供应商承诺的总量。

descriptionstring
可为 null

套餐销售说明,尚未填写时为 null。

description_enstring
可为 null

英文描述,尚未提供时为 null。

featuresobject

套餐能力采用带类型对象而非代码数组:[] 无法区分“不支持热点”和“信息未知”,false 与 null 可以。

appsobject[]

按操作系统区分的应用支持状态。

数组中不存在的应用表示信息未知,并非“支持”。 仅已列出的条目属于供应商承诺;目前只声明了 TikTok。

有意不提供合并字段:真实目录中有 2,465 个套餐支持 iPhone 上的 TikTok,但不支持 Android。一个合并标记会将其全部归为“不支持”,从而误判近三分之一的目录。

androidstring

supported(声明支持)、blocked(声明不支持)、unknown(声明未覆盖此操作系统)。开放枚举。

supportedblockedunknown
appstring

小写应用代码(例如 tiktok)。

iosstring

supported(声明支持)、blocked(声明不支持)、unknown(声明未覆盖此操作系统)。开放枚举。

supportedblockedunknown
notestring
可为 null
—
hotspotboolean
可为 null

向其他设备共享 Wi-Fi。null 表示未声明,与 false 不同。

kyc_requiredboolean
可为 null

使用前需要身份验证(KYC)。null 表示未声明。

smsboolean
可为 null

短信功能。false 表示无法接收短信,因此也无法接收银行验证码。null 表示未声明。

voiceboolean
可为 null

语音通话。false 表示供应商明确不支持语音,纯数据线路不能接听电话。null 表示未声明。

fupobject
可为 null

高速流量耗尽后的处理方式。null 表示未声明限速政策。

behaviorstring
可为 null

throttle(限速)、cutoff(断网)或 null(未声明)。开放枚举。

throttlecutoffnull
high_speed_bytesinteger · int64
可为 null

开始限速前可全速使用的字节数。

notestring
可为 null
—
speed_kbpsinteger
可为 null

高速额度用尽后的速率(kbps)。断网或未声明时为 null,不同于整个套餐的速率上限 network.speed_cap_kbps。

marketstring

套餐的供应系统,为可扩展枚举,客户端必须忽略未知值。它决定是否有库存及可用售后操作:domestic 销售套件,支持追加、取消和用量查询;international 按需向供应商下单,因此没有库存。

domesticinternational
namestring
—
name_enstring
可为 null

英文名称,尚未提供时为 null。

networkobject

套餐可用的网络。

apnstring
可为 null

某些无法自动配置的 Android 设备需要手动输入的 APN。此信息用于编写安装指南,否则每次都会变成客服咨询。null 表示未声明。

carriersobject[]

套餐实际使用的运营商网络。这是 eSIM 的无线网络规格,并非供应商。

namestring
—
generationsstring[]
可为 null

套餐可使用的网络代际(["4g", "5g"])。null 表示未声明,并非“仅支持 2G”。

speed_cap_kbpsinteger
可为 null

整个套餐的速率上限(kbps),不同于高速额度用尽后适用的 fup.speed_kbps。

priceobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
tagsstring[]

规范化的商业标签(小写、使用连字符),也用于匹配密钥的目录限制。目前没有套餐带标签,因此在卖方开始添加标签之前,?tag= 返回空列表。

validityobject

套餐有效期及开始计时的条件。

daysinteger
—
install_by_daysinteger
可为 null

购买后可扫描二维码或安装 eSIM 的天数。null 表示未声明,并非“随时可以安装”。

labelstring
—
reclaim_on_expiryboolean
可为 null

供应商在套餐到期时回收订阅,此后不能加购或换套餐。销售续费时需了解此窗口。null 表示未声明。

starts_whenstring
可为 null

计时起点:on_install(安装时)、on_purchase(购买时)或 null。这直接影响有效期计算;为 null 时不要承诺具体到期日期。

on_installon_purchasenull
unused_valid_daysinteger
可为 null

套餐未使用时可存放至过期的天数。null 表示未声明,并非无限期。此字段与 install_by_days 有意区分:一个是保管期限,一个是安装期限。

modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_cursorstring
可为 null

获取下一页时请原样传回。null 是唯一的结束信号,即使当前页少于 page_size 条,也可能仍有后续页面。

page_sizeinteger

服务器用于本页的最大记录数,已应用上限,并非 items 中的实际元素数量。

policyobject
可为 null

此供应商追加新套餐时的处理方式。null 表示套餐无法追加,或尚未确认供应商政策,不能据此推断;全部字段为 false 的对象则表示保证不会取消任何套餐,两者含义不同。

notestring
可为 null
—
requires_cancel_firstboolean

新套餐下单前会取消正在使用的套餐,因为此供应商不叠加套餐。请在客户点击追加新套餐按钮之前告知。

stackingboolean

新套餐的有效期和额度是否叠加到当前套餐。

totalinteger · int64
可为 null

匹配筛选条件的套餐总数。集合较大、计数成本高时(国际套餐或无 market 筛选)为 null。此计数发生在密钥限制及组织价格检查之前,表示目录匹配数而非可购数。

warningsobject[]

列表呈现方式的原因;无异常时为空。封闭代码集:filtered_by_key_package_filters、filtered_by_provider_scope、no_price_for_org、price_filter_removed_rows、provider_disabled、capability_missing,分别代表密钥限制、组织供应源范围、未定价、价格筛选、供应商停用、未声明功能。count 为涉及行数,无法量化时为 null。

codestring
—
filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing
countinteger · int64
可为 null
—
messagestring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
internal.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="GET"
REQ_PATH="/v1/esims/$ID/plan-options"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "items": [
      {
        "capabilities": {
          "cancel": {
            "restriction": "code_not_disclosed",
            "supported": true
          },
          "plan_change": {
            "policy": {
              "note": "<note>",
              "requires_cancel_first": true,
              "stacking": true
            },
            "supported": true
          },
          "usage_check": {
            "supported": true
          }
        },
        "code": "TKE-VN-30D-X3K9F",
        "coverage": {
          "countries": [
            "CN"
          ],
          "country_count": 1,
          "group": "country",
          "region": "<region>"
        },
        "data": {
          "daily_bytes": 1073741824,
          "label": "1GB/ngày",
          "model": "daily",
          "reset": {
            "at": "00:00",
            "note": "<note>",
            "timezone": "UTC+8"
          },
          "total_bytes": null
        },
        "description": "<description>",
        "description_en": "<description_en>",
        "features": {
          "apps": [
            {
              "android": "blocked",
              "app": "tiktok",
              "ios": "supported",
              "note": "<note>"
            }
          ],
          "hotspot": true,
          "kyc_required": false,
          "sms": false,
          "voice": false
        },
        "fup": {
          "behavior": "throttle",
          "high_speed_bytes": 1048576,
          "note": "<note>",
          "speed_kbps": 128
        },
        "market": "international",
        "name": "eSIM Trung Quốc Mainland Multi - 1GB/ngày - 24 ngày",
        "name_en": "<name_en>",
        "network": {
          "apn": "e-ideas",
          "carriers": [
            {
              "name": "China Unicom"
            }
          ],
          "generations": [
            "4g",
            "5g"
          ],
          "speed_cap_kbps": 1
        },
        "price": {
          "amount": 273000,
          "currency": "VND"
        },
        "tags": [],
        "validity": {
          "days": 24,
          "install_by_days": 365,
          "label": "24 ngày",
          "reclaim_on_expiry": true,
          "starts_when": "on_install",
          "unused_valid_days": 1
        }
      }
    ],
    "mode": "live",
    "next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
    "page_size": 50,
    "policy": {
      "note": "<note>",
      "requires_cancel_first": true,
      "stacking": true
    },
    "total": 128,
    "warnings": []
  },
  "ok": true
}
GET/v1/esims/{id}/refund-requests

eSIM 退款申请记录(仅限会员)

scope esims:readget_esims__id__refund-requests

所需权限范围: esims:read.

仅限已授权的正式会员密钥。按最新优先返回会员eSIM最多50条退款申请;next_cursor和total为null。has_open_request表示存在待审核申请。组织及测试密钥返回capability.not_supported。

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
has_open_requestboolean
—
itemsobject[]
—
decided_atstring · date-time
可为 null
—
decision_notestring
可为 null
—
idstring · uuid
—
order_idstring · uuid
—
order_item_idstring · uuid
—
reasonstring
—
refundedobject
可为 null
—
requested_atstring · date-time
—
statusstring
—
pendingapprovedrejected
suggestedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_cursorstring
可为 null

获取下一页时请原样传回。null 是唯一的结束信号,即使当前页少于 page_size 条,也可能仍有后续页面。

page_sizeinteger
可为 null

服务器用于本页的最大记录数,已应用上限,并非 items 中的实际元素数量。

totalinteger · int64
可为 null

符合筛选条件的记录数量。统计成本过高时为 null,请勿据此判断是否结束,应以 next_cursor 为准。

warningsobject[]

列表呈现方式的原因;无异常时为空。封闭代码集:filtered_by_key_package_filters、filtered_by_provider_scope、no_price_for_org、price_filter_removed_rows、provider_disabled、capability_missing,分别代表密钥限制、组织供应源范围、未定价、价格筛选、供应商停用、未声明功能。count 为涉及行数,无法量化时为 null。

codestring
—
filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing
countinteger · int64
可为 null
—
messagestring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
internal.not_found
422
capability.not_supported
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_member_live_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="GET"
REQ_PATH="/v1/esims/$ID/refund-requests"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "has_open_request": true,
    "items": [
      {
        "decided_at": "2026-07-11T08:12:30Z",
        "decision_note": "<decision_note>",
        "id": "018f2b00-0000-7000-8000-00000000009a",
        "order_id": "018f2b00-0000-7000-8000-00000000009a",
        "order_item_id": "018f2b00-0000-7000-8000-000000000000",
        "reason": "<reason>",
        "refunded": null,
        "requested_at": "2026-07-11T08:12:30Z",
        "status": "pending",
        "suggested": {
          "amount": 273000,
          "currency": "VND"
        }
      }
    ],
    "mode": "live",
    "next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
    "page_size": 50,
    "total": 128,
    "warnings": []
  },
  "ok": true
}
POST/v1/esims/{id}/refund-requests

创建 eSIM 退款申请(仅限会员)

scope esims:write必须提供 Idempotency-Keypost_esims__id__refund-requests

所需权限范围: esims:write.

仅限已授权的正式会员密钥。使用Idempotency-Key为会员自己的eSIM提交退款申请,管理员批准前不转移资金。组织及测试密钥返回capability.not_supported。测试模式请取消eSIM以验证虚拟钱包退款。

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

请求头 (1)

Idempotency-Keystring必填

客户端生成的字符串:相同密钥和请求体只执行一次,重试返回原结果。范围为 api_key_id(§11),不同密钥属于不同命令。

请求体必填application/json

字段类型约束说明
reasonstring
必填

退款理由,去除首尾空白后为 5 至 1000 个字符。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
decided_atstring · date-time
可为 null
—
decision_notestring
可为 null
—
idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
order_idstring · uuid
—
order_item_idstring · uuid
—
reasonstring
—
refundedobject
可为 null
—
requested_atstring · date-time
—
statusstring
—
pendingapprovedrejected
suggestedobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
internal.not_found
409
esim.refund_not_eligibleesim.refund_request_pendingidempotency.conflict
422
capability.not_supported
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_member_live_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="POST"
REQ_PATH="/v1/esims/$ID/refund-requests"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"reason":"<reason>"}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "decided_at": "2026-07-11T08:12:30Z",
    "decision_note": "<decision_note>",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "mode": "live",
    "order_id": "018f2b00-0000-7000-8000-00000000009a",
    "order_item_id": "018f2b00-0000-7000-8000-000000000000",
    "reason": "<reason>",
    "refunded": null,
    "requested_at": "2026-07-11T08:12:30Z",
    "status": "pending",
    "suggested": {
      "amount": 273000,
      "currency": "VND"
    }
  },
  "ok": true
}

请求体示例

json
{
  "reason": "<reason>"
}
GET/v1/esims/{id}/usage

已使用流量

scope esims:readget_esims__id__usage

所需权限范围: esims:read.

读取 eSIM 的已用与剩余流量,并附带数据时间戳 updated_at(真实新鲜度)。对于仅按需查询的供应商(目前为 SkyFi)的 eSIM,此调用会将一次扫描加入队列并最多等待约 15 秒获取结果,因此响应最长可能需要 ~15 秒,返回的数据来自刚完成的那次扫描。若扫描失败、同一 eSIM 距上次扫描不足 15 秒或等待超时,不会返回错误,而是返回最近保存的数据,请查看 updated_at。其他供应商返回定期更新的已保存数据。

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
esim_idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
usageobject
可为 null

eSIM 流量使用统计,从未查询过时 updated_at = null。

expires_atstring · date-time
可为 null
—
remaining_bytesinteger · int64
可为 null
—
sourcestring
可为 null
—
pollwebhook
total_bytesinteger · int64
可为 null
—
updated_atstring · date-time
可为 null
—
used_bytesinteger · int64
可为 null
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
422
capability.not_supported
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="GET"
REQ_PATH="/v1/esims/$ID/usage"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "esim_id": "018f2b00-0000-7000-8000-000000000000",
    "mode": "live",
    "usage": {
      "expires_at": "2026-08-10T00:00:00Z",
      "remaining_bytes": 5368709120,
      "source": "poll",
      "total_bytes": 5368709120,
      "updated_at": "2026-07-11T09:03:11Z",
      "used_bytes": 5368709120
    }
  },
  "ok": true
}

钱包

钱包余额

GET/v1/wallet/balance

钱包余额

scope wallet:readget_wallet_balance

所需权限范围: wallet:read.

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
availableobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
balanceobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
credit_limitobject

金额。/v1 全部使用统一结构,字段不会在对象和裸数字之间切换。

amountinteger · int64

以 currency 最小单位表示的整数(VND 无辅币单位)。

currencystring
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="GET"
REQ_PATH="/v1/wallet/balance"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "available": {
      "amount": 273000,
      "currency": "VND"
    },
    "balance": {
      "amount": 273000,
      "currency": "VND"
    },
    "credit_limit": {
      "amount": 273000,
      "currency": "VND"
    },
    "mode": "live"
  },
  "ok": true
}

Webhook

Webhook 配置、投递日志及模拟器

POST/v1/testmode/webhooks/fail-next

模拟下一次 webhook 失败(仅限测试密钥)

scope webhook:managepost_testmode_webhooks_fail-next

所需权限范围: webhook:manage.

请求体必填application/json

字段类型约束说明
countinteger
—

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
endpoint_idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
testmode_fail_nextinteger
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbidden
404
internal.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="POST"
REQ_PATH="/v1/testmode/webhooks/fail-next"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"count":1}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "endpoint_id": "018f2b00-0000-7000-8000-000000000000",
    "mode": "live",
    "testmode_fail_next": 1
  },
  "ok": true
}

请求体示例

json
{
  "count": 1
}
POST/v1/testmode/webhooks/fire

发送测试 webhook 事件(仅限测试密钥)

scope webhook:managepost_testmode_webhooks_fire

所需权限范围: webhook:manage.

请求体必填application/json

字段类型约束说明
dataobject

部分覆盖示例载荷中的 data 字段。

event_typestring
必填

要模拟触发的 Webhook 事件类型。

order.completedorder.failedesim.deliveredesim.activatedesim.usage_thresholdesim.expiringwallet.low_balancecatalog.updated

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
delivery_idstring · uuid
—
event_idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbidden
404
webhook.not_configuredinternal.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="POST"
REQ_PATH="/v1/testmode/webhooks/fire"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"data":{},"event_type":"order.completed"}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "delivery_id": "018f2b00-0000-7000-8000-000000000000",
    "event_id": "018f3c00-0000-7000-8000-0000000000b0",
    "mode": "live"
  },
  "ok": true
}

请求体示例

json
{
  "data": {},
  "event_type": "order.completed"
}
GET/v1/webhooks

列出 webhook 端点

scope webhook:manageget_webhooks

所需权限范围: webhook:manage.

仅返回调用 API 密钥的端点。密钥绝不查看其他密钥的端点,即使两个密钥属于同一组织(§5.11:绑定于 api_key_id,测试与正式环境不共享)。

尚未配置时返回 200 和空数组,而非 404;集合始终存在,只是当前没有元素。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
itemsobject[]
—
activeboolean

false 表示已停止接收新事件,仅在组织通过后台暂停或 API 密钥被撤销时发生(同一事务内联动关闭)。通过 CHECK_HEALTH 的 PUT /v1/webhooks/{id} 可重新启用。

created_atstring · date-time
—
eventsstring[]

为空表示接收全部。

idstring · uuid

端点 ID,用于 /v1/webhooks/{id}。每次创建都会生成新 ID,删除后重建得到的是另一个端点,而非恢复旧端点。

last_delivery_atstring · date-time
可为 null

通过此端点最后投递的时间。null 表示从未投递,不同于“投递失败”;合作伙伴反馈未收到 webhook 时应首先检查。

secret_last4string

Webhook 密钥的末四个字符,可用于核对手持密钥是否与系统签名密钥一致,而无需任何端点重新泄露密钥。完整密钥仅在创建时显示一次。

urlstring
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_cursorstring
可为 null

获取下一页时请原样传回。null 是唯一的结束信号,即使当前页少于 page_size 条,也可能仍有后续页面。

page_sizeinteger
可为 null

服务器用于本页的最大记录数,已应用上限,并非 items 中的实际元素数量。

totalinteger · int64
可为 null

符合筛选条件的记录数量。统计成本过高时为 null,请勿据此判断是否结束,应以 next_cursor 为准。

warningsobject[]

列表呈现方式的原因;无异常时为空。封闭代码集:filtered_by_key_package_filters、filtered_by_provider_scope、no_price_for_org、price_filter_removed_rows、provider_disabled、capability_missing,分别代表密钥限制、组织供应源范围、未定价、价格筛选、供应商停用、未声明功能。count 为涉及行数,无法量化时为 null。

codestring
—
filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing
countinteger · int64
可为 null
—
messagestring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="GET"
REQ_PATH="/v1/webhooks"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "items": [
      {
        "active": true,
        "created_at": "2026-07-11T08:12:30Z",
        "events": [
          "order.completed"
        ],
        "id": "018f2b00-0000-7000-8000-00000000009a",
        "last_delivery_at": "2026-07-11T08:12:30Z",
        "secret_last4": "a3f9",
        "url": "https://partner.example.com/hooks/tke"
      }
    ],
    "mode": "live",
    "next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
    "page_size": 50,
    "total": 128,
    "warnings": []
  },
  "ok": true
}
POST/v1/webhooks

创建 Webhook 端点

scope webhook:managepost_webhooks

所需权限范围: webhook:manage.

为调用密钥创建 webhook 端点。保存前,服务器会向 URL POST 一个已签名的 ping 事件(CHECK_HEALTH)。未获 2xx 则不保存并返回 422 webhook.health_check_failed。必须使用公开 https URL,内部或元数据 IP 返回 422 webhook.url_not_allowed。

webhook_secret 仅在创建时显示一次,无法再次读取。丢失后须在面板轮换,旧密钥还会并行有效 24 小时(§8.4)。

密钥已有端点时返回 409 webhook.already_configured,即使端点已暂停(is_active: false)。暂停仍保留 URL、密钥及日志。若需重建,先 DELETE /v1/webhooks/{id} 再创建。

请求体必填application/json

字段类型约束说明
eventsstring[]

为空表示接收全部。未知值返回 400 internal.validation_failed(字段 events)。

urlstring · uri
必填
—

响应

201成功

成功

字段类型约束说明
dataobject
必填
—
activeboolean

false 表示已停止接收新事件,仅在组织通过后台暂停或 API 密钥被撤销时发生(同一事务内联动关闭)。通过 CHECK_HEALTH 的 PUT /v1/webhooks/{id} 可重新启用。

created_atstring · date-time
—
eventsstring[]

为空表示接收全部。

health_checkstring
—
passed
idstring · uuid

端点 ID,用于 /v1/webhooks/{id}。每次创建都会生成新 ID,删除后重建得到的是另一个端点,而非恢复旧端点。

last_delivery_atstring · date-time
可为 null

通过此端点最后投递的时间。null 表示从未投递,不同于“投递失败”;合作伙伴反馈未收到 webhook 时应首先检查。

modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
secret_last4string

Webhook 密钥的末四个字符,可用于核对手持密钥是否与系统签名密钥一致,而无需任何端点重新泄露密钥。完整密钥仅在创建时显示一次。

urlstring
—
webhook_secretstring

仅在创建时显示一次(前缀 whsec_)。

okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
409
webhook.already_configured
422
webhook.health_check_failedwebhook.url_not_allowed
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="POST"
REQ_PATH="/v1/webhooks"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"events":["order.completed"],"url":"https://partner.example.com/hooks/tke"}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "active": true,
    "created_at": "2026-07-11T08:12:30Z",
    "events": [
      "order.completed"
    ],
    "health_check": "passed",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "last_delivery_at": "2026-07-11T08:12:30Z",
    "mode": "live",
    "secret_last4": "a3f9",
    "url": "https://partner.example.com/hooks/tke",
    "webhook_secret": "<webhook secret — chỉ hiện đúng một lần>"
  },
  "ok": true
}

请求体示例

json
{
  "events": [
    "order.completed"
  ],
  "url": "https://partner.example.com/hooks/tke"
}
GET/v1/webhooks/{id}

获取单个 webhook 端点

scope webhook:manageget_webhooks__id_

所需权限范围: webhook:manage.

路径参数 (1)

idstring必填

Webhook 端点 ID(POST /v1/webhooks 或 GET /v1/webhooks 返回的 id)。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
activeboolean

false 表示已停止接收新事件,仅在组织通过后台暂停或 API 密钥被撤销时发生(同一事务内联动关闭)。通过 CHECK_HEALTH 的 PUT /v1/webhooks/{id} 可重新启用。

created_atstring · date-time
—
eventsstring[]

为空表示接收全部。

idstring · uuid

端点 ID,用于 /v1/webhooks/{id}。每次创建都会生成新 ID,删除后重建得到的是另一个端点,而非恢复旧端点。

last_delivery_atstring · date-time
可为 null

通过此端点最后投递的时间。null 表示从未投递,不同于“投递失败”;合作伙伴反馈未收到 webhook 时应首先检查。

modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
secret_last4string

Webhook 密钥的末四个字符,可用于核对手持密钥是否与系统签名密钥一致,而无需任何端点重新泄露密钥。完整密钥仅在创建时显示一次。

urlstring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
webhook.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="GET"
REQ_PATH="/v1/webhooks/$ID"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "active": true,
    "created_at": "2026-07-11T08:12:30Z",
    "events": [
      "order.completed"
    ],
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "last_delivery_at": "2026-07-11T08:12:30Z",
    "mode": "live",
    "secret_last4": "a3f9",
    "url": "https://partner.example.com/hooks/tke"
  },
  "ok": true
}
PUT/v1/webhooks/{id}

更新 Webhook 端点

scope webhook:manageput_webhooks__id_

所需权限范围: webhook:manage.

路径参数 (1)

idstring必填

Webhook 端点 ID(POST /v1/webhooks 或 GET /v1/webhooks 返回的 id)。

请求体必填application/json

字段类型约束说明
eventsstring[]

为空表示接收全部。未知值返回 400 internal.validation_failed(字段 events)。

urlstring · uri
必填
—

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
activeboolean

false 表示已停止接收新事件,仅在组织通过后台暂停或 API 密钥被撤销时发生(同一事务内联动关闭)。通过 CHECK_HEALTH 的 PUT /v1/webhooks/{id} 可重新启用。

created_atstring · date-time
—
eventsstring[]

为空表示接收全部。

idstring · uuid

端点 ID,用于 /v1/webhooks/{id}。每次创建都会生成新 ID,删除后重建得到的是另一个端点,而非恢复旧端点。

last_delivery_atstring · date-time
可为 null

通过此端点最后投递的时间。null 表示从未投递,不同于“投递失败”;合作伙伴反馈未收到 webhook 时应首先检查。

modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
secret_last4string

Webhook 密钥的末四个字符,可用于核对手持密钥是否与系统签名密钥一致,而无需任何端点重新泄露密钥。完整密钥仅在创建时显示一次。

urlstring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
webhook.not_found
422
webhook.health_check_failedwebhook.url_not_allowed
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="PUT"
REQ_PATH="/v1/webhooks/$ID"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"events":["order.completed"],"url":"https://partner.example.com/hooks/tke"}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "active": true,
    "created_at": "2026-07-11T08:12:30Z",
    "events": [
      "order.completed"
    ],
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "last_delivery_at": "2026-07-11T08:12:30Z",
    "mode": "live",
    "secret_last4": "a3f9",
    "url": "https://partner.example.com/hooks/tke"
  },
  "ok": true
}

请求体示例

json
{
  "events": [
    "order.completed"
  ],
  "url": "https://partner.example.com/hooks/tke"
}
DELETE/v1/webhooks/{id}

删除 webhook 端点(停止接收新事件)

scope webhook:managedelete_webhooks__id_

所需权限范围: webhook:manage.

删除端点后,调用密钥不再接收新事件。

webhook_secret 会随端点删除而失去。通过 POST /v1/webhooks 重建会生成新 id 和新密钥,必须更新签名验证函数。若只需暂停并保留密钥,请使用面板中的“暂停”。

完整投递日志保留用于对账,但被删端点的投递记录无法重放。

等待重试的 pending 投递会以 endpoint_disabled 原因停止,并保留日志(§8.5)。

不属于调用密钥或已删除的 id 返回 404 webhook.not_found,绝不会静默返回 200。

路径参数 (1)

idstring必填

Webhook 端点 ID(POST /v1/webhooks 或 GET /v1/webhooks 返回的 id)。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
deleted_atstring · date-time
—
idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
webhook.not_found
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="DELETE"
REQ_PATH="/v1/webhooks/$ID"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "deleted_at": "2026-07-11T08:12:30Z",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "mode": "live"
  },
  "ok": true
}
GET/v1/webhooks/deliveries

Webhook 投递日志

scope webhook:manageget_webhooks_deliveries

所需权限范围: webhook:manage.

查询参数 (5)

pageinteger选填默认值 1min 1

页码从 1 开始。超出数据末尾时返回 items: [] 和真实 total(200,非 404)。

page_sizeinteger选填默认值 50min 1max 200

每页记录数,默认 50,上限 200;超过上限时限制为 200,不报错。

event_typestring选填

按事件类型筛选(参见 webhook 事件目录)。

statusstring选填
允许的值:pendingdeliveredfailed

按投递状态筛选。?status=failed 用于主动查询式 webhook 对账(§13)。未知值不会报错,筛选条件会被忽略并返回完整日志。

event_idstring · uuid选填

同一事件的所有投递尝试(包括重放)。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
itemsobject[]
—
attemptsinteger
—
created_atstring · date-time
—
event_idstring · uuid

事件标识。重放会创建一个新投递记录,但保留同一 event_id;请按 event_id 去重,不要按投递 id 去重。

event_typestring
—
idstring · uuid
—
last_attempt_atstring · date-time
可为 null
—
next_retry_atstring · date-time
可为 null
—
response_codeinteger
可为 null
—
statusstring
—
pendingdeliveredfailed
webhook_idstring · uuid
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_cursorstring
可为 null

获取下一页时请原样传回。null 是唯一的结束信号,即使当前页少于 page_size 条,也可能仍有后续页面。

page_sizeinteger
可为 null

服务器用于本页的最大记录数,已应用上限,并非 items 中的实际元素数量。

totalinteger · int64
可为 null

符合筛选条件的记录数量。统计成本过高时为 null,请勿据此判断是否结束,应以 next_cursor 为准。

warningsobject[]

列表呈现方式的原因;无异常时为空。封闭代码集:filtered_by_key_package_filters、filtered_by_provider_scope、no_price_for_org、price_filter_removed_rows、provider_disabled、capability_missing,分别代表密钥限制、组织供应源范围、未定价、价格筛选、供应商停用、未声明功能。count 为涉及行数,无法量化时为 null。

codestring
—
filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing
countinteger · int64
可为 null
—
messagestring
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
webhook.not_configured
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="GET"
REQ_PATH="/v1/webhooks/deliveries"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "items": [
      {
        "attempts": 3,
        "created_at": "2026-07-11T08:12:30Z",
        "event_id": "018f3c00-0000-7000-8000-0000000000b0",
        "event_type": "order.completed",
        "id": "018f2b00-0000-7000-8000-00000000009a",
        "last_attempt_at": "2026-07-11T09:05:00Z",
        "next_retry_at": "2026-07-11T09:10:00Z",
        "response_code": 200,
        "status": "pending",
        "webhook_id": "018f2b00-0000-7000-8000-000000000000"
      }
    ],
    "mode": "live",
    "next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
    "page_size": 50,
    "total": 128,
    "warnings": []
  },
  "ok": true
}
POST/v1/webhooks/deliveries/{id}/replay

重新投递 webhook

scope webhook:managepost_webhooks_deliveries__id__replay

所需权限范围: webhook:manage.

路径参数 (1)

idstring必填

单次 webhook 投递 ID(来自 GET /v1/webhooks/deliveries 的 items[].id)。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
attemptsinteger
—
created_atstring · date-time
—
event_idstring · uuid

事件标识。重放会创建一个新投递记录,但保留同一 event_id;请按 event_id 去重,不要按投递 id 去重。

event_typestring
—
idstring · uuid
—
last_attempt_atstring · date-time
可为 null
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
next_retry_atstring · date-time
可为 null
—
response_codeinteger
可为 null
—
statusstring
—
pendingdeliveredfailed
webhook_idstring · uuid
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspended
404
webhook.delivery_not_foundwebhook.not_configured
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="POST"
REQ_PATH="/v1/webhooks/deliveries/$ID/replay"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "attempts": 3,
    "created_at": "2026-07-11T08:12:30Z",
    "event_id": "018f3c00-0000-7000-8000-0000000000b0",
    "event_type": "order.completed",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "last_attempt_at": "2026-07-11T09:05:00Z",
    "mode": "live",
    "next_retry_at": "2026-07-11T09:10:00Z",
    "response_code": 200,
    "status": "pending",
    "webhook_id": "018f2b00-0000-7000-8000-000000000000"
  },
  "ok": true
}

测试模式

仅在api-testing主机使用tke_test_或tke_member_test_测试密钥。模拟所有者的测试eSIM和数据,不使用真实余额或供应商。会员测试模式不支持Webhook、批量订单或人工审核退款申请。

POST/v1/testmode/esims/{id}/simulate

模拟测试 eSIM 生命周期(仅限测试密钥)

scope esims:writepost_testmode_esims__id__simulate

所需权限范围: esims:write.

仅限tke_test_或tke_member_test_测试密钥。对所有者的测试eSIM设置用量、安装状态、到期、限速或下一操作的模拟供应商拒绝。正文至少包含一个字段;空正文返回422 testmode.invalid_scenario。与正式模式相同,通过GET /v1/esims/{id}和/usage读取结果。套餐变更及取消规则共用,不调用真实供应商。

路径参数 (1)

idstring必填

已售 eSIM 的稳定 ID,不是可能复用的 ICCID。

请求体必填application/json

字段类型约束说明
data_used_mbinteger · int64

已使用流量(MB,以二进制 1 MiB 为单位)。超出套餐额度时截至额度上限,表示流量耗尽场景,而非错误。

expire_atstring · date-time

设置明确的到期时间(ISO-8601 UTC)。

expire_nowboolean

true 表示立即让套餐过期(esim_status 变为 expired)。

provider_rejectboolean

模拟供应商拒绝下一次操作(追加/取消)。

statusstring

eSIM 配置的技术生命周期,采用供应商术语,不同于 eSIM 端点返回的业务状态 esim_status。

releasedinstalledenableddisabled
throttledboolean

true 表示线路已限速(无限套餐超过高速额度)。

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
cancellableobject

eSIM 是否仍可取消及原因,请在调用 POST /v1/esims/{order_item_id}/cancel 前读取。此区块是明确回答,始终存在,不为 null。

allowedboolean
—
disclosed_atstring · date-time
可为 null

代码离开系统的时间(ISO-8601 UTC),无人查看时为 null。客户声称未收到代码却无法取消时,可据此核查。

reasonstring
可为 null

不可取消原因:code_disclosed(已发送或显示代码)、wrong_status(状态不允许)、expired(已过期)、not_supported(未声明取消能力)。allowed = true 时为 null,与 esim.not_cancellable 的 meta.reason 使用同一代码集。

code_disclosedwrong_statusexpirednot_supportednull
external_refstring
可为 null

您的订单引用(下单时发送的 external_ref),用于将 eSIM 对应到您的订单。未提供时为 null。

iccidstring
可为 null
—
idstring · uuid

eSIM ID,用于所有 /v1/esims/{id}/… 路径,也就是 webhook 中的 order_item_id。若只有 ICCID,请调用 GET /v1/esims?iccid=… 获取 id。

installobject
可为 null

安装此 eSIM 所需的全部信息。null 表示您未请求此信息(未传 include=lpa),并不表示 eSIM 尚无安装代码;后者会返回此对象且 lpa: null。

包含此对象的响应始终带有 Cache-Control: no-store。

android_urlstring
可为 null
—
apnstring
可为 null

设备无法自动获取配置时需输入的接入点名称(APN)。当前版本始终为 null,表示“未知”,而非“不需要”。

ios_urlstring
可为 null
—
lpastring
可为 null

eSIM 激活码,属于可销售的机密。仅凭此字符串即可在您的系统生成二维码。

matching_idstring
可为 null
—
qr_code_base64string
可为 null

二维码的 PNG data-URI。仅在详情端点请求 include=qr 时返回,列表绝不包含(每行约 11 KB,100 行约 1.1 MB);列表中请使用 lpa 自行生成二维码。

smdp_addressstring
可为 null
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
msisdnstring
可为 null
—
order_idstring · uuid
—
package_codestring
可为 null

目录中的套餐代码,用于将此 eSIM 对应回您的目录。仅当源套餐已从目录移除时为 null。

package_namestring

供人阅读、可能变化的显示名称。请勿用作对账键。

planobject
可为 null

此 eSIM 当前使用的套餐。

current_codestring
—
expires_atstring · date-time
可为 null
—
started_atstring · date-time
可为 null
—
simulatedobject

应用场景后的模拟状态。

esim_statestring

测试 eSIM 的技术生命周期。正式环境来自 smdp_status,但测试 eSIM 没有可读取的 SM-DP+ 配置,因此放在此处,与其他测试专用字段并列。

releasedinstalledenableddisabled
last_viastring

最近修改此 eSIM 的流程。

open_apisimulateseed
viastring

创建此测试 eSIM 的流程。

open_apisimulateseed
smdp_statusstring
可为 null
—
statusstring
—
updated_atstring · date-time
—
usageobject
可为 null

eSIM 流量使用统计,从未查询过时 updated_at = null。

expires_atstring · date-time
可为 null
—
remaining_bytesinteger · int64
可为 null
—
sourcestring
可为 null
—
pollwebhook
total_bytesinteger · int64
可为 null
—
updated_atstring · date-time
可为 null
—
used_bytesinteger · int64
可为 null
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbidden
404
internal.not_found
422
testmode.invalid_scenario
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"

METHOD="POST"
REQ_PATH="/v1/testmode/esims/$ID/simulate"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"data_used_mb":4096,"expire_at":"2026-07-11T08:12:30Z","expire_now":true,"provider_reject":true,"status":"enabled","throttled":true}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "cancellable": {
      "allowed": true,
      "disclosed_at": "2026-07-11T08:12:30Z",
      "reason": "code_disclosed"
    },
    "external_ref": "po-1001",
    "iccid": "8984012345678901234",
    "id": "018f2b00-0000-7000-8000-00000000009a",
    "install": {
      "android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
      "apn": "<apn>",
      "ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
      "lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
      "matching_id": "MATCH-ABC123",
      "qr_code_base64": "<PNG base64 — đã rút gọn>",
      "smdp_address": "smdp.example.com"
    },
    "mode": "live",
    "msisdn": "+84900000000",
    "order_id": "018f2b00-0000-7000-8000-00000000009a",
    "package_code": "TKE-VN-30D-X3K9F",
    "package_name": "Tên gói hiển thị",
    "plan": {
      "current_code": "TKE-VN-30D-X3K9F",
      "expires_at": "2026-08-10T00:00:00Z",
      "started_at": "2026-07-11T08:12:30Z"
    },
    "simulated": {
      "esim_state": "released",
      "last_via": "open_api",
      "via": "open_api"
    },
    "smdp_status": "released",
    "status": "delivered",
    "updated_at": "2026-07-11T09:03:11Z",
    "usage": {
      "expires_at": "2026-08-10T00:00:00Z",
      "remaining_bytes": 5368709120,
      "source": "poll",
      "total_bytes": 5368709120,
      "updated_at": "2026-07-11T09:03:11Z",
      "used_bytes": 5368709120
    }
  },
  "ok": true
}

请求体示例

json
{
  "data_used_mb": 4096,
  "expire_at": "2026-07-11T08:12:30Z",
  "expire_now": true,
  "provider_reject": true,
  "status": "enabled",
  "throttled": true
}
POST/v1/testmode/reset

重置测试数据(仅限测试密钥)

scope orders:writepost_testmode_reset

所需权限范围: orders:write.

请求头 (1)

Idempotency-Keystring选填

请求体选填application/json

字段类型约束说明
reasonstring
—

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
esim_states_deletedinteger · int64
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
order_items_deletedinteger · int64
—
orders_deletedinteger · int64
—
wallet_balanceinteger · int64

重置后的测试钱包余额,始终为 0。不会删除账本,而是通过抵销分录将余额归零。

okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbidden
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="POST"
REQ_PATH="/v1/testmode/reset"   # them query thi noi thang vao day TRUOC khi ky
BODY='{"reason":"Reset test data"}'

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data-raw "$BODY"

响应示例

json
{
  "data": {
    "esim_states_deleted": 1,
    "mode": "live",
    "order_items_deleted": 1,
    "orders_deleted": 1,
    "wallet_balance": 1
  },
  "ok": true
}

请求体示例

json
{
  "reason": "Reset test data"
}
POST/v1/testmode/seed

生成测试示例数据(仅限测试密钥)

scope orders:writepost_testmode_seed

所需权限范围: orders:write.

请求头 (1)

Idempotency-Keystring选填

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
already_seededboolean
—
esims_createdinteger
—
modestring

调用密钥的环境,与X-TKE-Mode标头一致。组织密钥使用tke_live_/tke_test_,会员密钥使用tke_member_live_/tke_member_test_。正式和测试主机校验密钥模式。

testlive
orders_createdinteger
—
seededboolean
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbidden
422
testmode.no_sellable_package
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="POST"
REQ_PATH="/v1/testmode/seed"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG" \
  -H "Idempotency-Key: $(uuidgen)"

响应示例

json
{
  "data": {
    "already_seeded": true,
    "esims_created": 1,
    "mode": "live",
    "orders_created": 1,
    "seeded": true
  },
  "ok": true
}
GET/v1/testmode/status

测试模式概览(仅限测试密钥)

scope esims:readget_testmode_status

所需权限范围: esims:read.

响应

200成功

成功

字段类型约束说明
dataobject
必填
—
base_url_testingstring

测试模式主机。仅使用tke_test_或tke_member_test_密钥;调用正式主机返回403 partner.wrong_host。

capabilitiesobject
—
bulk_ordersboolean
—
cancel_refundboolean
—
refund_requestsboolean
—
webhooksboolean
—
checklistobject[]

根据同一所有者在测试模式下的实际API记录计算集成进度。Webhook步骤仅适用于组织。

doneboolean
—
labelstring
—
last_atstring · date-time
可为 null
—
stepstring
—
driftobject

模拟用量循环的启用状态、间隔及最后运行时间。阈值Webhook仅发送给支持Webhook的组织。

enabledboolean
—
interval_secsinteger · int64
—
last_run_atstring · date-time
可为 null
—
modestring
—
testlive
readyboolean

密钥所有者是否已完成所有受支持的检查步骤。会员无需测试Webhook。

sample_countsobject
—
test_esimsinteger · int64
—
test_ordersinteger · int64
—
seededboolean

密钥所有者是否已有测试订单和eSIM样本数据。

test_key_countinteger · int64
—
wallet_balanceinteger · int64

密钥所有者的虚拟VND测试钱包余额,与正式钱包隔离。

webhookobject
—
endpoint_urlstring
可为 null
—
fail_nextinteger
—
statusstring
可为 null
—
okboolean
必填
—
true

错误响应

所有错误均返回 { ok: false, error } 及正确 HTTP 状态,错误不返回 200,详细含义参见错误码页面。

400
internal.validation_failed
401
partner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reused
403
partner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbidden
429
partner.rate_limited
503
partner.endpoint_disabledinternal.service_unavailable

调用示例

所有 TKE-VN-30D-X3K9F 值均需自行替换,真实套餐代码请查询 GET /v1/catalog/packages.

bash
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.

KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"

METHOD="GET"
REQ_PATH="/v1/testmode/status"   # them query thi noi thang vao day TRUOC khi ky
BODY=""

TS="$(date +%s000)"                 # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"

curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
  -H "Accept-Language: zh-CN" \
  -H "X-TKE-Key: $KEY_ID" \
  -H "X-TKE-Timestamp: $TS" \
  -H "X-TKE-Nonce: $NONCE" \
  -H "X-TKE-Signature: $SIG"

响应示例

json
{
  "data": {
    "base_url_testing": "<base_url_testing>",
    "capabilities": {
      "bulk_orders": true,
      "cancel_refund": true,
      "refund_requests": true,
      "webhooks": true
    },
    "checklist": [
      {
        "done": true,
        "label": "<label>",
        "last_at": "2026-07-11T08:12:30Z",
        "step": "<step>"
      }
    ],
    "drift": {
      "enabled": true,
      "interval_secs": 1,
      "last_run_at": "2026-07-11T08:12:30Z"
    },
    "mode": "test",
    "ready": true,
    "sample_counts": {
      "test_esims": 1,
      "test_orders": 1
    },
    "seeded": true,
    "test_key_count": 1,
    "wallet_balance": 1,
    "webhook": {
      "endpoint_url": "https://partner.example.com/hooks/tke",
      "fail_next": 1,
      "status": "completed"
    }
  },
  "ok": true
}