# Webhook 通知

> 接收并验签 Onerway 支付通知，正确应答与幂等处理，并在未收到通知时查询交易结果。

Onerway 将支付、绑卡、订阅、预授权与退款等交易的最终结果以 Webhook 通知推送到商户服务端。本页说明所有接入方式共用的通知处理契约；收银台、Web SDK 与 API 直连各自的接入指南只补充该接入方式涉及的通知类型与额外注意事项。

本页的投递、验签、应答与去重规则适用于下表所列通知。分账及分账回退通知使用 body `sign` 验签，其通知地址和应答方式见[分账结果通知](/zh/payments/api-reference/webhooks/profit-share-result)。

Ethoca / RDR 报备状态通知也使用通知体中的 `sign` 验签，通知地址在商户后台配置，应答返回收到的 `id`。完整要求见 [Ethoca 报备状态通知](/zh/payments/api-reference/webhooks/ethoca-enrollment-changed)和 [RDR 报备状态通知](/zh/payments/api-reference/webhooks/rdr-enrollment-changed)。

## 通知投递

Onerway 将通知以 HTTP POST 发送到创建交易时传入的 `notifyUrl`。报文结构按场景分别见：

| 通知 | 场景 |
| --- | --- |
| [支付结果通知](/zh/payments/api-reference/webhooks/payment-result) | 普通支付成功、失败、超时关闭或取消 |
| [保存支付方式结果通知](/zh/payments/api-reference/webhooks/payment-method-result) | 保存支付方式（绑卡，`txnType=BIND_CARD`）的结果 |
| [订阅扣款通知](/zh/payments/api-reference/webhooks/subscription-payment) | 初始订阅、续费、变更、取消等订阅生命周期事件 |
| [预授权、请款与撤销通知](/zh/payments/api-reference/webhooks/authorization-capture) | 预授权（`txnType=AUTH`）、请款（`txnType=CAPTURE`）与撤销（`txnType=VOID`）结果 |
| [退款结果通知](/zh/payments/api-reference/webhooks/refund-result) | 退款结果（`txnType=REFUND`） |
| [退款审核拒绝通知](/zh/payments/api-reference/webhooks/refund-audit-rejected) | Onerway 审核拒绝退款申请（`notifyType=REFUND_AUDIT`） |

退款通知发送到原交易请求中的 `notifyUrl`。仅在 Onerway 审核拒绝退款申请时发送 `REFUND_AUDIT`。取消退款申请成功不发送通知，请处理[申请或取消退款](/zh/payments/api-reference/endpoints/create-or-cancel-refund)的响应。

支付结果通过 Webhook 或查询接口确认，`returnUrl` 跳转与客户端事件不作为支付成功的依据。申请退款（`refundType=0`）时，响应中的 `respCode=20000` 表示 Onerway 已受理请求，不代表退款成功。

## 验签

上表所列通知必须使用 header `X-Rh-Signature` 验签，不要依赖通知 body 中的 `sign` 字段：`sign` 仅使用第一个启用的密钥计算，密钥轮换期间，它可能与你使用当前配置的 `SECRET` 计算出的签名不同。验签规则与不参与验签的字段见[请求签名](/zh/payments/get-started/request-signing#webhook-%E9%AA%8C%E7%AD%BE)。

## 应答与重试

处理完成后必须返回 HTTP 200，使用 `Content-Type: text/plain`，并在响应体中原样返回该通知的 `transactionId`。未收到成功响应时，Onerway 以 30 分钟间隔重试，最多 3 次。

## 幂等去重

单笔交易可能收到多次通知，必须按 `transactionId` 幂等去重：同一 `transactionId` 的重复通知只处理一次，但仍须正常应答。

绑卡、订阅并绑卡、预授权及后续请款或撤销等场景会产生多笔 `transactionId` 各不相同的关联通知，应各自幂等处理，并用 `paymentId`、`contractId` 等业务标识关联到同一支付意图或订阅合约。

## 状态判断

- `status` 表示本次操作的结果，例如 `S` 成功、`F` 失败。
- `paymentStatus` 表示支付意图的状态，例如预授权成功后为 `A`、请款成功后为 `S`、撤销成功后为 `N`（已关闭）。

处理预授权、请款与撤销结果时，结合 `paymentId` 与 `paymentStatus` 判断资金处于冻结中、已扣款还是已释放。退款结果使用该笔退款的 `transactionId` 与 `status` 处理。各通知对应的字段和取值见其 API Reference 页面。

## 查询结果与通知不一致时如何处理

以下规则通用于支付、退款等场景。当查询结果与已收到的 Webhook 不一致时，比较同一笔交易、同一次操作的结果：

- 查询返回的状态既不是成功（`S`）也不是失败（`F`），但 Webhook 已通知成功或失败时，以 Webhook 为准。
- 其他情况以查询结果为准，包括查询已返回成功（`S`）或失败（`F`）的情况。

## 按需查询结果

收到成功（`S`）或失败（`F`）的 Webhook 后即可处理相应的支付或退款结果，不需要再查询确认。

对于支付，客户已返回商户页面但尚未收到 Webhook，或需要对账时，可按递增间隔查询支付结果，直到查询返回成功（`S`）、失败（`F`）或收到 Webhook。

对于退款，等待 Webhook 通知退款结果即可，无需持续轮询。需要核对进度或对账时，可使用[查询退款记录](/zh/payments/api-reference/endpoints/query-refunds)，按退款交易号或原支付交易号查询。

支付结果查询接口按接入方式选择：收银台接入与 API 直连接入使用[查询交易记录](/zh/payments/api-reference/endpoints/query-transactions)；Web SDK 接入使用创建支付时保存的 `paymentId` 调用[查询支付记录](/zh/payments/api-reference/endpoints/query-payments)。

## 上线前检查

- 已对上表所列通知使用 `X-Rh-Signature` 验签，验签失败的通知不处理。
- 对上表所列通知，处理后返回 HTTP 200 与 `transactionId`，且按 `transactionId` 幂等去重。
- Webhook 端点能接收所用场景涉及的全部通知类型。
- 已参考[沙盒测试](/zh/payments/get-started/testing)在沙盒环境验证成功、失败与重试场景。
