一笔订单从创建、付款到入账的完整生命周期。
商户服务端 KukoPay 买家浏览器
│ POST /orders │ │
│─────────────────────▶│ │
│ checkout_url │ │
│◀─────────────────────│ │
│ 重定向买家到 checkout_url │
│───────────────────────────────────────────────▶│
│ │◀──── 输入支付信息 ───────│
│ │ │
│ payment.succeeded │ │
│◀─────────────────────│──── 回跳 return_url ───▶│return_url 只负责买家体验,不是支付凭据。买家可能关掉页面或回跳可能被伪造。请以验签后的 payment.succeeded Webhook 作为履约依据。
| 状态 | 含义 |
|---|---|
pending | 已创建,等待买家付款 |
paid | 支付成功,净额已记入商户钱包 |
partially_refunded | 已发生部分退款 |
refunded | 已全额退款 |
failed | 渠道明确返回失败或取消 |
expired | 超过 24 小时仍未支付,由对账任务关闭 |
后台对账任务会核对未决支付与退款。即使渠道通知暂时丢失、买家又关闭了页面,平台仍会重新读取渠道结果并补入账、补通知或关闭订单。
买家在收银台可以随时更换支付方式,例如先选支付宝,中途返回改用微信支付或银行卡。checkout_url 在有效期(默认 24 小时)内都可以回来继续付款。
为保证一笔订单只收一次钱,平台在切换前会先取消买家尚未完成的那笔支付,确认取消成功后才发起新的支付。如果取消时发现买家恰好已经付款,平台直接按这笔付款入账,不会再让买家付第二次。
因此一张订单在付款过程中可能先后对应多笔渠道支付,订单对象的 payment_id 会随之变化。请以 trade_no / out_trade_no 和 payment.succeeded 事件对账,不要把 payment_id 当作订单的唯一标识。
极少数情况下,买家的付款会在订单已经关闭之后才到达,例如订单已由另一笔付款支付,或已超时关闭。平台对这类付款的处理规则是:
| 到达时订单的状态 | 平台的处理 |
|---|---|
pending(尚未支付) | 按这笔付款正常入账,发送 payment.succeeded |
其他任何状态(paid、partially_refunded、refunded、expired、failed) | 全额原路退回买家,发送 payment.duplicate_refunded |
退回的钱从未计入商户钱包,所以不会影响商户余额,也不会产生手续费或退款流水。payment.duplicate_refunded 只是通知,商户无需任何操作。同一订单多次发生这种情况时,只会发送一次该事件。
支付确认时,平台在同一结算事务内更新订单、计算手续费、增加钱包可用余额并写入对应账本流水。金额在 API 与账本中始终使用最小货币单位。