Tổng Kho eSIM
测试环境

测试模式

请在 api-testing.tongkhoesim.com 使用合作伙伴 tke_test_ 或会员 tke_member_test_ 密钥。虚拟余额和模拟 eSIM 与真实资金、库存和发票隔离。可用操作取决于密钥所有者;会员请查看批量订单、Webhook 和退款审核限制。

使用真实资金前请测试完整流程。参见 HMAC 签名 了解认证公式,以及 试用控制台 在浏览器中直接发送测试请求。

会员 OpenAPI

管理员按会员授予 OpenAPI 权限。在主侧栏打开 API 密钥,选择正式或测试模式后创建密钥;私密密钥仅显示一次。两种模式共用密钥数量限制。关闭权限将阻止两种模式,但仍可撤销密钥。

正式模式使用会员真实 VND 钱包,无信用额度。测试使用独立虚拟钱包和模拟 eSIM,可在测试页添加余额、创建或重置示例。测试订单不会出现在真实购买历史中。

两种模式均不支持会员批量订单和 Webhook。退款审核申请仅支持正式模式;取消测试 eSIM 可模拟退回虚拟钱包。测试不会调用真实供应商或开具真实 MISA 发票。不支持的操作返回 capability.not_supported。

会员 API 端点

按密钥区分两种主机

请使用密钥对应主机,主机错误会在业务处理前被拒绝。

主机基础 URL接受的密钥
正式https://api.tongkhoesim.com/v1tke_live_ / tke_member_live_
测试https://api-testing.tongkhoesim.com/v1tke_test_ / tke_member_test_

创建测试密钥

在控制台测试模式创建 tke_test_,保存仅显示一次的密钥。首个测试密钥会自动调用 POST /v1/testmode/seed。

正式与测试的 7 项差异

项目正式(api、tke_live_)测试(api-testing、tke_test_)
主机api.tongkhoesim.comapi-testing.tongkhoesim.com,主机错误返回 403
钱包组织真实钱包独立虚拟钱包,可通过控制台或管理员调整无限充值
库存真实 esim_profiles虚拟库存,无限生成模拟 eSIM
发放真实上游运营商确定性模拟:相同输入生成相同 ICCID/LPA(LPA:1$testmode-smdp.tongkhoesim.com$…)
流量使用从运营商读取真实用量每隔几分钟自动增加,75/90% 阈值通知
Webhook真实正式事件测试事件,可手动触发与 fail-next
账本真实财务账本隔离虚拟账本,只追加不删除,绝不混入真实账本
POST

/v1/testmode/seed

POST /v1/testmode/seed 创建可立即测试的数据集。按组织幂等,重复调用返回 already_seeded: true,不生成重复数据。

  • 余额充足的测试钱包
  • 按组织价格创建 3 个真实套餐订单,各含 1 个 eSIM
  • 三种状态:未安装、已用 40%、已过期
bash
#!/usr/bin/env bash
# Requires: bash + openssl + uuidgen.

KEY_ID="tke_test_REPLACE_WITH_YOUR_KEY_ID"
SECRET="REPLACE_WITH_YOUR_SECRET"

METHOD="POST"
REQ_PATH="/v1/testmode/seed"
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 "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
{
  "ok": true,
  "data": {
    "seeded": true,
    "already_seeded": false,
    "orders_created": 3,
    "esims_created": 3
  }
}

自动流量增长(drift)

已启用测试 eSIM 默认每 5 分钟增加用量,直到用完或到期,并在 75% 和 90% 触发 esim.usage_threshold。GET /v1/testmode/status 返回启用状态与间隔。

/v1/testmode/* 接口

仅在 api-testing.tongkhoesim.com 使用 tke_test_ 调用,不提供旧路径别名。

方法路径用途
GET/v1/testmode/status就绪状态、检查项、密钥/订单/eSIM 数量、钱包、Webhook 和 drift 状态
POST/v1/testmode/seed按组织幂等创建示例数据
POST/v1/testmode/reset软删除测试订单/eSIM,通过冲销分录归零钱包
POST/v1/testmode/esims/{order_item_id}/simulate模拟用量、状态、到期、限速及下次运营商拒绝
POST/v1/testmode/webhooks/fire立即向测试 Webhook 发送示例事件({event_type})
POST/v1/testmode/webhooks/fail-next强制后续 N 次投递返回 503,测试重试
状态变更审计来源(via)
via触发时机ref_id 含义
open_api使用测试密钥直接调用 /v1 下单、充值、取消或模拟调用密钥的 api_keys.id
simulate成员或代理管理员通过控制台触发模拟成员或管理员的用户 ID
seed通过 /v1/testmode/seed 创建的数据空
POST

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

test-mode-only

POST /v1/testmode/esims/{order_item_id}/simulate 可设置用量、状态、到期、带宽,或令下次充值/取消被模拟运营商拒绝一次。

bash
#!/usr/bin/env bash
KEY_ID="tke_test_REPLACE_WITH_YOUR_KEY_ID"
SECRET="REPLACE_WITH_YOUR_SECRET"
ORDER_ITEM_ID="REPLACE_WITH_ORDER_ITEM_ID"

METHOD="POST"
REQ_PATH="/v1/testmode/esims/$ORDER_ITEM_ID/simulate"
BODY='{"data_used_mb":4096,"status":"enabled"}'

TS="$(date +%s000)"
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 "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"
# No Idempotency-Key required: state mutation is intrinsically idempotent.
json
{
  "ok": true,
  "data": {
    "order_item_id": "018f2b00-0000-7000-8000-000000000001",
    "esim_state": "enabled",
    "running_package_code": "TKE-VN-30D-X3K9F",
    "running_started_at": "2026-07-11T07:00:00Z",
    "running_expires_at": "2026-08-10T07:00:00Z",
    "data_bytes": 5368709120,
    "used_bytes": 4294967296,
    "remaining_bytes": 1073741824,
    "throttled": false,
    "via": "simulate",
    "last_via": "simulate",
    "mode": "test",
    "updated_at": "2026-07-11T09:15:00Z"
  }
}

测试模式错误码

错误码HTTP含义与解决方法
testmode.live_key_forbidden403使用正式密钥调用 /v1/testmode/*,请改用同组织的 tke_test_。
testmode.invalid_scenario422请求体为空、未提供字段,或状态不在 released/installed/enabled/disabled 中。
testmode.not_test_item422order_item_id 不属于测试订单,不可模拟修改正式数据。
testmode.no_sellable_package422组织没有已定价套餐,密钥仍创建成功,仅示例生成失败。
partner.wrong_host403密钥与主机不匹配,请切换到错误响应中指定的主机。

完整目录请见 错误码页面 。标准 /v1 认证流程在测试逻辑之前执行。

测试 Webhook:fire 与 fail-next

POST /v1/testmode/webhooks/fire 无需真实订单即可发送事件。请求体:{ "event_type": "order.completed", "data": {...} },省略 data 时自动生成示例。

POST /v1/testmode/webhooks/fail-next { "count": 1 } 强制后续 N 次投递 503,随后自动清除,无需关闭真实接收端。