Skip to content

V1 业务通知 ​

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

概述 ​

  • 一个 Sugumart tenant 只能配置一个业务通知 URL,通过 POST /openapi/v1/shop/callback 设置。
  • 多个开放应用访问同一 tenant 时共享该业务通知配置;任一应用重新设置都会覆盖当前 URL 并轮换 Secret。
  • Sugumart 使用 POST 向该 URL 发送 application/json 请求。
  • 业务通知 URL 支持 HTTP 或 HTTPS,正式环境建议使用 HTTPS;不得包含 URL fragment 或内嵌账号密码。
  • 通知只包含当前 Access Token 所绑定店铺的数据。
  • 同一 URL 接收全部商品审核、订单和物流事件,不按事件分别配置 URL。
  • 业务通知可能重复或乱序到达,接收方必须实现幂等处理和状态版本比较。
  • 事件发生时尚未配置通知 URL 或通知已停用,该事件不会排队,也不会在后续启用配置后补发。

业务通知配置接口见店铺配置,状态枚举见V1 状态附录。

业务通知 URL 与 OAuth 授权回调 URL 是两个不同概念。OAuth redirect_uri 由浏览器访问并携带 code/state;本文的 URL 由 Sugumart 服务端使用 POST 调用并通过 Webhook Secret 签名。

本文中的事件信封是 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
notifications.batch合并投递同一店铺的一组业务通知Notification[]

事件边界:

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

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是事件数据;结构由事件类型决定

单条业务通知使用上述事件信封。notifications.batch 使用相同信封,但 data 为 Notification[],详见批通知事件。

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.created、order.updated 和 order.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.shipped、logistics.warehouse_received 和 logistics.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.submitted、product.review.approved 和 product.review.rejected 使用 ProductReviewEventData。

ProductReviewEventData ​

字段类型说明
product_idstring(uuid)Sugumart 商品 ID
namestring当前商品名称
statusstring当前商品生命周期状态:pending_review、approved 或 rejected
review_statusstring当前审核状态:pending、approved 或 rejected
previous_review_statusstring本次变化前的审核状态:draft、pending、approved 或 rejected
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 早于 approved 或 rejected;最终决定事件不得被同版本的提交事件覆盖。
  • 管理员可在待上架阶段撤销已通过结果,因此同一版本可能先收到 approved、后收到 rejected。两个最终决定版本相同时,以 status_at 较新的事件为准。
  • 如查询结果与业务通知不一致,以商品详情接口为准。

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 批通知事件 ​

notifications.batch 用于在一次请求中投递多条业务通知。外层事件信封代表本次批次,data 是由一个或多个 Notification 组成的数组。每个数组元素都是完整的单条通知信封,且 event 不得为 notifications.batch,因此批通知不能嵌套。

Notification ​

字段类型必填说明
idstring是单条通知唯一 ID;批次重试时保持不变
eventstring是单条通知事件名称,不得为 notifications.batch
api_versionstring是固定为 v1
shop_idstring(uuid)是Sugumart 店铺 ID,必须与外层 shop_id 相同
occurred_atstring是单条业务状态变化时间,ISO 8601 UTC
dataobject是单条事件数据,结构由 event 决定

批次中的通知按 occurred_at 升序排列;相同时间的元素顺序不代表业务先后。接收方仍须根据每条通知的 id 去重,并使用 status_at 或 review_version 处理乱序。

notifications.batch Example ​

json
{
  "id": "evt_batch_01K1W2Y4T8H6F3D9N7M5Q2P0CX",
  "event": "notifications.batch",
  "api_version": "v1",
  "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
  "occurred_at": "2026-08-06T04:00:00.000Z",
  "data": [
    {
      "id": "evt_01K1W2X1B4M8C6V9N3Q7T5H0PA",
      "event": "order.updated",
      "api_version": "v1",
      "shop_id": "82dbf488-3467-4825-afc4-31dbc91c115c",
      "occurred_at": "2026-08-06T03:58: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-06T03:57:55.000Z",
        "resource_url": "/openapi/v1/orders/87eb4314-22a0-4d72-861e-9118f952191b"
      }
    }
  ]
}

2.3.7 签名验证 ​

设置业务通知配置时取得的 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.8 响应与重试 ​

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

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

重试约定:

  • 同一事件的所有重试保持相同 id、event、occurred_at 和请求体。
  • 每次重试会重新生成 X-Sugumart-Timestamp 和 X-Sugumart-Signature。
  • 重试可能造成事件乱序,接收方应使用 status_at 判断业务状态先后。
  • 当前每轮首次投递失败后最多重试 3 次,间隔依次为 30 秒、120 秒和 600 秒;仍失败则停止自动投递。平台可能调整这一运行策略,接收方不应依赖重试次数保证数据完整性。
  • 批通知采用整批确认:接收端返回非 2xx 时会重试整个批次,不支持只确认数组中的部分通知。

2.3.9 幂等与数据一致性 ​

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