Webhook 回调
订单支付、发货、Profile 状态或退款完成时,会向你在 API 凭证里配置的 callback URL 发送 POST 请求。验签规则与调用 Open API 时完全一致。
三个要点:
- 对外只有 3 种
eventType(见下表)。 - 每次推送的是整单快照(与 查单 结构相同),不是增量 patch。
- 想知道「这次具体变了什么」,优先看
changeHints,再对照orderStatus/deliveryStatus/items[].profiles[]。
配置回调地址
方式一: 管理后台 → API 凭证 → 填写回调 URL
方式二: 调用接口 POST /open-api/v1/webhook/set
json
{ "callbackUrl": "https://your-server.com/openapi/callback" }事件类型
| eventType | 何时推送 |
|---|---|
ORDER_PAID | 余额扣款成功,订单进入履约 |
DELIVERY_UPDATED | 发货进度或 Profile 状态有变化(见 常见场景)。仅在该订单确有变更时推送 |
REFUND_COMPLETED | 退款已入账(含同步退款与异步退款完成) |
发货、安装、激活、用量更新等变化都使用
DELIVERY_UPDATED,不会另发ESIM_STATUS、DATA_USAGE等事件名。请根据 payload 字段与changeHints判断细节。
推荐处理流程
text
收到 POST → 验签 → 快速返回 HTTP 200 → 异步处理业务
若 eventType == DELIVERY_UPDATED:
1. 读取 changeHints,按类型更新 UI / 本地状态
2. 用整单 payload 覆盖本地订单快照(便于对账)
若 eventType == ORDER_PAID:
标记已支付,等待后续 DELIVERY_UPDATED
若 eventType == REFUND_COMPLETED:
标记退款完成,更新退款金额幂等: 同一 orderNo + eventType 可能因重试重复投递,请按此组合去重。
如何读懂 changeHints
Webhook Body 是全量订单快照。changeHints 表示「相对该订单、同类型事件的上一次成功投递」发生了哪些变化:
- 首次
DELIVERY_UPDATED,或没有历史快照时,按「相对空快照」推断(例如首次出现iccid→ICCID_READY)。 - 一次推送可含多个 hint。
- 重试投递时
changeHints与首次相同。
发货与安装
| changeHints | 含义 | 建议动作 |
|---|---|---|
ICCID_READY | 首次出现 ICCID | 展示卡号、引导安装 |
QR_CODE_READY | 首次出现安装二维码 URL | 展示 QR |
ACTIVATION_CODE_READY | 首次出现 SM-DP+ 激活码 | 展示 LPA 串 |
订单与子项状态
| changeHints | 含义 | 建议动作 |
|---|---|---|
DELIVERY_STATUS_CHANGED | 主单 deliveryStatus 变化 | 更新发货进度 |
ORDER_STATUS_CHANGED | 主单 orderStatus 变化 | 更新订单状态 |
ITEM_STATUS_CHANGED | 子项 itemStatus 变化 | 更新子单状态 |
PROFILE_LIFECYCLE_CHANGED | Profile lifecycleStatus 变化 | 更新单卡生命周期 |
ESIM_STATUS_CHANGED | Profile esimStatus 变化 | 记录 eSIM 状态(补充字段) |
SMDP_STATUS_CHANGED | Profile smdpStatus 变化 | 记录安装过程状态(补充字段) |
套餐与用量
| changeHints | 含义 | 建议动作 |
|---|---|---|
PLAN_USE_STARTED | planUseStatus 变为 STARTED | 标记套餐已开始使用 |
PLAN_USE_ENDED | planUseStatus 变为 ENDED | 标记套餐已结束 |
USAGE_UPDATED | 流量相关字段变化 | 更新用量展示;实时用量可另调 profile/usage |
退款与其他
| changeHints | 含义 | 建议动作 |
|---|---|---|
PROFILE_CANCELLED | Profile cancelled 变为 true | 标记卡已取消 |
REFUND_AMOUNT_UPDATED | 累计退款额增加 | 更新退款金额 |
ORDER_PAID | 配合 ORDER_PAID 事件 | 标记已支付 |
REFUND_COMPLETED | 配合 REFUND_COMPLETED 事件 | 标记退款完成 |
ORDER_SNAPSHOT_SYNC | 有推送但未命中更细规则 | 用 payload 全量覆盖本地快照 |
状态字段取值
判断业务阶段时,优先使用 lifecycleStatus 与 changeHints。esimStatus / smdpStatus 为渠道相关原始值,不同套餐可能不同,仅作补充参考。
主单 deliveryStatus
| 值 | 含义 |
|---|---|
PENDING | 未发货 |
PARTIAL | 部分 Profile 已就绪 |
DELIVERED | 全部 Profile 已就绪 |
FAILED | 发货失败 |
主单 orderStatus(常用)
| 值 | 含义 |
|---|---|
PAID | 已支付,待履约 |
FULFILLING | 履约中 |
COMPLETED | 订单完成 |
REFUNDING | 退款处理中(通常不单独推 Webhook,以查单为准) |
REFUNDED | 已退款 |
子项 itemStatus
| 值 | 含义 |
|---|---|
PENDING | 待发码 |
DELIVERED | 已发码 |
ACTIVATING | 激活中 |
ACTIVATED | 已激活 |
FAILED | 失败 |
REFUNDED | 已退款 |
Profile lifecycleStatus(推荐)
| 值 | 含义 |
|---|---|
PENDING | 待发码 |
DELIVERED | 已发码(含 iccid / qr) |
ACTIVATING | 安装或激活进行中 |
ACTIVATED | 已激活 |
CANCELLED | 已取消 |
DELIVERY_UPDATED 常见场景
| 场景 | payload 中常见变化 |
|---|---|
| ICCID / 二维码 / 激活码就绪 | items[].iccid、qrCodeUrl、activationCode;deliveryStatus 可能变为 PARTIAL / DELIVERED |
| Profile 安装或 eSIM 状态变更 | items[].profiles[].esimStatus、smdpStatus |
| 套餐开始使用或结束 | items[].profiles[].planUseStatus、planUseStartTime、planUseEndTime |
| 流量或有效期更新 | items[].profiles[].dataUsageBytes、remainDataBytes、usagePercent 等 |
| Profile 激活或生命周期变化 | items[].profiles[].activated、lifecycleStatus |
| 退款审核拒绝等导致 Profile 回写 | items[].profiles[].cancelled 等;退款入账另见 REFUND_COMPLETED |
不会单独推送的情况
| 场景 | 说明 |
|---|---|
退款处理中(REFUNDING) | 退款接口可能返回 REFUNDING;入账前不会推 Webhook,请查单或等待 REFUND_COMPLETED |
| 账户充值审核通过 | 走账户流程,不在订单 Webhook 范围内 |
| 下单支付失败 | 未落单,无 Webhook |
推送规则
- 按订单维度推送;仅在该订单实际发生变更时发送,无变更则不推。
- 不同套餐支持的 Profile 字段可能不同,以 payload 中
items[].profiles[]实际返回为准。
请求格式
Header 与入站 Open API 一致(使用同一 AppKey 对应的 AppSecret 签名)。
ORDER_PAID 示例
json
{
"eventType": "ORDER_PAID",
"transactionId": "your-transaction-id",
"orderNo": "ORD20260101001",
"orderId": 123456,
"payStatus": "PAID",
"deliveryStatus": "PENDING",
"orderStatus": "PAID",
"currency": "USD",
"items": [
{
"itemNo": "2075463266738958341",
"packageCode": "PKG001",
"quantity": 1,
"itemStatus": "PAID"
}
]
}DELIVERY_UPDATED 示例
json
{
"eventType": "DELIVERY_UPDATED",
"transactionId": "your-transaction-id",
"orderNo": "ORD20260101001",
"orderId": 123456,
"payStatus": "PAID",
"deliveryStatus": "DELIVERED",
"orderStatus": "COMPLETED",
"currency": "USD",
"changeHints": ["ICCID_READY", "QR_CODE_READY", "DELIVERY_STATUS_CHANGED", "PROFILE_LIFECYCLE_CHANGED"],
"items": [
{
"itemNo": "2075463266738958341",
"packageCode": "PKG001",
"quantity": 1,
"itemStatus": "DELIVERED",
"profiles": [
{
"profileId": "2075464693179805698",
"iccid": "8901234567890123456",
"esimTranNo": "26071006120045",
"qrCodeUrl": "https://cdn.example.com/qr/xxx.png",
"activationCode": "LPA:1$rsp-eu.simlessly.com$...",
"esimStatus": "IN_USE",
"lifecycleStatus": "ACTIVATED",
"planUseStatus": "STARTED",
"dataUsageBytes": 524288000
}
]
}
]
}REFUND_COMPLETED 示例
json
{
"eventType": "REFUND_COMPLETED",
"transactionId": "your-transaction-id",
"orderNo": "ORD20260101001",
"orderId": 123456,
"payStatus": "REFUNDED",
"deliveryStatus": "DELIVERED",
"orderStatus": "REFUNDED",
"refundAmount": 3.50,
"currency": "USD",
"items": [
{
"itemNo": "ITEM001",
"packageCode": "PKG001",
"quantity": 1,
"itemStatus": "REFUNDED"
}
]
}完整字段定义见 OpenAPI Schema 中的 WebhookCallbackPayload。
重试与接入建议
投递失败会自动重试(默认最多 8 次,指数退避)。
- 先验签,再处理业务逻辑
- 尽快返回 HTTP 200,耗时操作放异步队列
- 按
orderNo+eventType做幂等,并保存整单快照便于对账