Skip to content

V1 Callback Notifications

回调通知模块用于 Sugumart 主动向店铺配置的唯一回调 URL 推送商品审核、订单与物流状态变化。通知为异步事件提示;调用方需要最新完整资料时,应再调用对应的商品详情或订单详情接口查询。

概述

  • 一个店铺只能配置一个回调 URL,通过 POST /openapi/v1/shop/callback 设置。
  • Sugumart 使用 POST 向该 URL 发送 application/json 请求。
  • 回调 URL 必须使用 HTTPS,不得包含 URL fragment 或内嵌账号密码。
  • 通知只包含当前 Access Token 所绑定店铺的数据。
  • 同一 URL 接收全部商品审核、订单和物流事件,不按事件分别配置 URL。
  • 回调可能重复或乱序到达,接收方必须实现幂等处理和状态版本比较。

回调配置接口见店铺配置,状态枚举见V1 状态附录

本文中的事件信封是 Sugumart 向接收端发送的 Webhook 请求体,不是 V1 API 的统一响应信封。接收端只需按本文约定返回 2xx,无需返回 { "success": true, "data": ... }


2.3.1 通知事件

事件触发条件data 类型
order.created新订单首次同步到 Sugumart 并可被当前店铺查询OrderEventData
order.updated订单状态、付款状态、取消回复状态或其他对外订单字段发生变化OrderEventData
order.cancelled订单取消交易完成,订单主状态变为 cancelledOrderEventData
product.review.submitted商品成功提交审核,review_status 变为 pendingProductReviewEventData
product.review.approved当前版本的商品审核通过,review_status 变为 approvedProductReviewEventData
product.review.rejected当前版本的商品审核未通过,review_status 变为 rejectedProductReviewEventData
logistics.shipped集运仓完成出库,履约状态变为 shippedLogisticsEventData
logistics.warehouse_received大陆快递包裹被集运仓签收入库,预报单状态变为 receivedLogisticsEventData
logistics.delivered已取得买家末端签收事实,订单展示状态变为 deliveredLogisticsEventData

事件边界:

  • order.created 只在订单首次建立时发送;后续同步变化使用 order.updated
  • order.cancelled 是取消完成通知。仅进入 InCancel 或等待卖家确认时,使用 order.updated
  • product.review.submitted 表示平台已受理一次新的审核提交,不表示审核已经通过。
  • 同一商品重新提交审核时会产生新的 review_version;通过或拒绝事件只对应其携带的审核版本。
  • 商品审核通过不表示商品已经上架;审核通过后仍需调用商品上架接口。
  • logistics.shipped 表示包裹已从集运仓出库,不表示买家已经签收。
  • logistics.warehouse_received 表示大陆快递包裹已进入集运仓,不表示跨境运输完成。
  • logistics.delivered 只以露天末端配送的签收、已送达或买家取货事实为准。WMS 的“到达统仓”不得触发该事件。

2.3.2 请求格式

Request Headers

Header类型说明
Content-Typestring固定为 application/json
User-AgentstringSugumart 回调客户端标识
X-Sugumart-Event-Idstring事件唯一 ID,与请求体 id 相同
X-Sugumart-Eventstring事件名称,与请求体 event 相同
X-Sugumart-Timestampstring签名生成时间,Unix 秒
X-Sugumart-SignaturestringHMAC-SHA256 签名的小写十六进制结果

Request Body

字段类型必填说明
idstring事件唯一 ID;同一次事件重试时保持不变
eventstring事件名称,取值见通知事件表
api_versionstring固定为 v1
shop_idstring(uuid)Sugumart 店铺 ID
occurred_atstring业务状态变化时间,ISO 8601 UTC
dataobject事件数据;结构由事件类型决定

Request Example

json
{
  "id": "evt_01K1W27D9A7M6T0C3P4R8H2N5Q",
  "event": "logistics.warehouse_received",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-04T08:30:00.000Z",
  "data": {
    "order_id": "87eb4314-22a0-4d72-861e-9118f952191b",
    "ruten_order_id": "24080412345678",
    "fulfillment_id": "9b2d0bb1-8d4e-41ac-9c65-3a6fd514f98d",
    "fulfillment_no": "RT202608040001",
    "status": "received",
    "previous_status": "shipped",
    "tracking_number": "SF123456789CN",
    "warehouse_code": "20089",
    "status_at": "2026-08-04T08:29:42.000Z",
    "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
  }
}

2.3.3 订单事件数据

order.createdorder.updatedorder.cancelled 使用 OrderEventData

OrderEventData

字段类型说明
order_idstring(uuid)Sugumart 订单 ID
ruten_order_idstring露天订单号
statusstring当前订单主状态,见 V1 状态附录
previous_statusstring | null变化前订单主状态;order.created 时为 null
view_statusstring | null当前订单展示状态;尚不能计算时为 null
ruten_order_statusstring | null最近观察到的露天订单状态
ruten_pay_statusstring | null最近观察到的露天付款状态
ruten_respond_statusstring | null最近观察到的取消回复状态
changed_fieldsstring[]本次发生变化的公开字段路径;创建事件为空数组
status_atstring当前状态生效或被观察到的时间,ISO 8601 UTC
resource_urlstring获取最新订单详情的 V1 相对路径

order.created Example

json
{
  "id": "evt_01K1W21GTY66X5HZGF9WVHZA6A",
  "event": "order.created",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-04T08:00:00.000Z",
  "data": {
    "order_id": "87eb4314-22a0-4d72-861e-9118f952191b",
    "ruten_order_id": "24080412345678",
    "status": "pending_payment",
    "previous_status": null,
    "view_status": null,
    "ruten_order_status": "Unpaid",
    "ruten_pay_status": "Unpaid",
    "ruten_respond_status": null,
    "changed_fields": [],
    "status_at": "2026-08-04T08:00:00.000Z",
    "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
  }
}

order.updated Example

json
{
  "id": "evt_01K1W23WTPAQGM1CH58G35MT93",
  "event": "order.updated",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-04T08:10:00.000Z",
  "data": {
    "order_id": "87eb4314-22a0-4d72-861e-9118f952191b",
    "ruten_order_id": "24080412345678",
    "status": "pending_shipment",
    "previous_status": "pending_payment",
    "view_status": "pending_shipment",
    "ruten_order_status": "ReadyToShip",
    "ruten_pay_status": "Paid",
    "ruten_respond_status": null,
    "changed_fields": ["status", "view_status", "ruten_order_status", "ruten_pay_status"],
    "status_at": "2026-08-04T08:09:55.000Z",
    "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
  }
}

order.cancelled Example

json
{
  "id": "evt_01K1W2520E2KYHSMV8VB8TWR56",
  "event": "order.cancelled",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-04T08:20:00.000Z",
  "data": {
    "order_id": "87eb4314-22a0-4d72-861e-9118f952191b",
    "ruten_order_id": "24080412345678",
    "status": "cancelled",
    "previous_status": "pending_shipment",
    "view_status": null,
    "ruten_order_status": "Cancelled",
    "ruten_pay_status": "Paid",
    "ruten_respond_status": "Approved",
    "changed_fields": ["status", "ruten_order_status", "ruten_respond_status", "cancelled_at"],
    "status_at": "2026-08-04T08:19:58.000Z",
    "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
  }
}

2.3.4 物流事件数据

logistics.shippedlogistics.warehouse_receivedlogistics.delivered 使用 LogisticsEventData

LogisticsEventData

字段类型说明
order_idstring(uuid)Sugumart 订单 ID
ruten_order_idstring露天订单号
fulfillment_idstring(uuid)Sugumart 履约 ID
fulfillment_nostringSugumart 集货单号
statusstring当前事件对应的物流状态
previous_statusstring | null变化前的同类物流状态;无法确定时为 null
tracking_numberstring | null当前物流阶段的追踪号;没有追踪号时为 null
warehouse_codestring | null露天物流仓 code;不适用时为 null
status_atstring当前物流状态发生时间,ISO 8601 UTC
resource_urlstring获取最新订单详情的 V1 相对路径

各事件的 status

事件status时间来源
logistics.shippedshipped集运仓出库时间
logistics.warehouse_receivedreceived集运仓签收入库时间
logistics.delivereddelivered买家末端签收或取货时间

logistics.shipped Example

json
{
  "id": "evt_01K1W29C4A91AA4YXYG8RMY8RQ",
  "event": "logistics.shipped",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-04T09:00:00.000Z",
  "data": {
    "order_id": "87eb4314-22a0-4d72-861e-9118f952191b",
    "ruten_order_id": "24080412345678",
    "fulfillment_id": "9b2d0bb1-8d4e-41ac-9c65-3a6fd514f98d",
    "fulfillment_no": "RT202608040001",
    "status": "shipped",
    "previous_status": "created",
    "tracking_number": "TW123456789",
    "warehouse_code": "20089",
    "status_at": "2026-08-04T08:59:42.000Z",
    "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
  }
}

logistics.warehouse_received Example

json
{
  "id": "evt_01K1W2D8X1Q0K4V7N5J3P6ABCD",
  "event": "logistics.warehouse_received",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-05T06:30:00.000Z",
  "data": {
    "order_id": "87eb4314-22a0-4d72-861e-9118f952191b",
    "ruten_order_id": "24080412345678",
    "fulfillment_id": "9b2d0bb1-8d4e-41ac-9c65-3a6fd514f98d",
    "fulfillment_no": "RT202608040001",
    "status": "received",
    "previous_status": "shipped",
    "tracking_number": "SF123456789CN",
    "warehouse_code": "20089",
    "status_at": "2026-08-05T06:29:42.000Z",
    "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
  }
}

logistics.delivered Example

json
{
  "id": "evt_01K1W2GJTV7HCNYYDTRB613KTV",
  "event": "logistics.delivered",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-08T02:15:00.000Z",
  "data": {
    "order_id": "87eb4314-22a0-4d72-861e-9118f952191b",
    "ruten_order_id": "24080412345678",
    "fulfillment_id": "9b2d0bb1-8d4e-41ac-9c65-3a6fd514f98d",
    "fulfillment_no": "RT202608040001",
    "status": "delivered",
    "previous_status": "shipped",
    "tracking_number": "TW123456789",
    "warehouse_code": "20089",
    "status_at": "2026-08-08T02:14:36.000Z",
    "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
  }
}

2.3.5 商品审核事件数据

product.review.submittedproduct.review.approvedproduct.review.rejected 使用 ProductReviewEventData

ProductReviewEventData

字段类型说明
product_idstring(uuid)Sugumart 商品 ID
namestring当前商品名称
statusstring当前商品生命周期状态:pending_reviewapprovedrejected
review_statusstring当前审核状态:pendingapprovedrejected
previous_review_statusstring本次变化前的审核状态:draftpendingapprovedrejected
review_versioninteger商品审核提交版本,正整数;同一商品每次重新提交审核时递增
rejected_reasonstring | null审核拒绝原因;仅 product.review.rejected 非空,最长 500 字符
submitted_atstring当前审核版本的提交时间,ISO 8601 UTC
reviewed_atstring | null当前审核版本的决定时间,ISO 8601 UTC;审核中为 null
status_atstring当前审核状态生效时间,ISO 8601 UTC;提交事件等于 submitted_at,审核决定事件等于 reviewed_at
resource_urlstring获取最新商品详情的 V1 相对路径

乱序处理规则:

  • 同一 product_id 应先比较 review_version,版本较小的事件不得覆盖版本较大的审核结果。
  • review_version 相同时,pending 早于 approvedrejected;最终决定事件不得被同版本的提交事件覆盖。
  • approvedrejected 不会同时成为同一审核版本的最终结果;如查询结果与回调不一致,以商品详情接口为准。

product.review.submitted Example

json
{
  "id": "evt_01K1W2KX6CPAH7Y4M8V3Q9T2NR",
  "event": "product.review.submitted",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-05T07:30:00.000Z",
  "data": {
    "product_id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
    "name": "轻量防泼水通勤背包",
    "status": "pending_review",
    "review_status": "pending",
    "previous_review_status": "draft",
    "review_version": 1,
    "rejected_reason": null,
    "submitted_at": "2026-08-05T07:30:00.000Z",
    "reviewed_at": null,
    "status_at": "2026-08-05T07:30:00.000Z",
    "resource_url": "/openapi/v1/products/a7b3c8df-bb08-46f0-9ca2-5597a32e0404"
  }
}

product.review.approved Example

json
{
  "id": "evt_01K1W2Q8EX6BH4Y7S9C5N0M3VT",
  "event": "product.review.approved",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-05T08:10:00.000Z",
  "data": {
    "product_id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
    "name": "轻量防泼水通勤背包",
    "status": "approved",
    "review_status": "approved",
    "previous_review_status": "pending",
    "review_version": 1,
    "rejected_reason": null,
    "submitted_at": "2026-08-05T07:30:00.000Z",
    "reviewed_at": "2026-08-05T08:10:00.000Z",
    "status_at": "2026-08-05T08:10:00.000Z",
    "resource_url": "/openapi/v1/products/a7b3c8df-bb08-46f0-9ca2-5597a32e0404"
  }
}

product.review.rejected Example

json
{
  "id": "evt_01K1W2T91P7DZ5C4A8M6H3Q0NX",
  "event": "product.review.rejected",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-06T03:20:00.000Z",
  "data": {
    "product_id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
    "name": "轻量防泼水通勤背包",
    "status": "rejected",
    "review_status": "rejected",
    "previous_review_status": "pending",
    "review_version": 2,
    "rejected_reason": "主图包含无法识别的促销文字,请修改后重新提交。",
    "submitted_at": "2026-08-06T02:45:00.000Z",
    "reviewed_at": "2026-08-06T03:20:00.000Z",
    "status_at": "2026-08-06T03:20:00.000Z",
    "resource_url": "/openapi/v1/products/a7b3c8df-bb08-46f0-9ca2-5597a32e0404"
  }
}

2.3.6 签名验证

设置回调配置时取得的 secret 用于验证通知来源。签名原文为:

text
X-Sugumart-Timestamp + "." + raw_request_body

计算方式:

text
HMAC-SHA256(secret, signature_payload)

计算结果编码为小写十六进制字符串,并与 X-Sugumart-Signature 做常量时间比较。

接收方应执行以下检查:

  1. 使用未经解析或重新序列化的原始请求体计算签名。
  2. 拒绝签名不匹配的请求。
  3. 检查 X-Sugumart-Timestamp 与服务器时间的偏差,防止重放攻击。
  4. 使用 X-Sugumart-Event-Id 或请求体 id 去重。

2.3.7 响应与重试

接收端完成签名验证并持久化事件后,应返回任意 2xx 响应。响应体可为空,Sugumart 不读取业务字段。

接收端结果Sugumart 行为
2xx本次投递成功,不再重试
2xx本次投递失败,进入重试
网络错误或连接失败本次投递失败,进入重试
响应超时本次投递失败,进入重试

重试约定:

  • 同一事件的所有重试保持相同 ideventoccurred_at 和请求体。
  • 每次重试会重新生成 X-Sugumart-TimestampX-Sugumart-Signature
  • 重试可能造成事件乱序,接收方应使用 status_at 判断业务状态先后。
  • 重试次数与间隔属于平台运行策略,不作为固定 API 契约;接收方不得依赖特定重试次数。

2.3.8 幂等与数据一致性

  • 接收方应以事件 id 作为幂等键;已成功处理的事件再次到达时直接返回 2xx
  • 不得只按 order_id + event 去重,同一订单可能多次产生 order.updated
  • 商品审核事件不得只按 product_id + event 去重;同一商品可能经过多个 review_version,每次投递仍以事件 id 去重。
  • 回调是状态变化提示,不是完整资源快照。需要完整字段时,使用 resource_url 对应的商品详情或订单详情接口查询。
  • 回调与查询结果不一致时,以对应商品详情或订单详情接口 data 中的最新结果为准。
  • 未识别的 event 或状态值应记录为可见错误,不应自动映射为已有状态。
  • 接收方不应在回调处理中记录完整签名 Secret、买家证件号码或其他敏感资料。