> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 鉴权与签名 FAQ

> 解答 Waffo API 鉴权中最常见的问题：API key 从哪里获取、请求与响应签名如何工作、Webhook 验签、A0001/A0002 排查以及 RSA 密钥生成。

商户最常问的鉴权与签名问题。完整契约见：
[Acquiring API Specification](/docs/api-reference/introduction)。

## 我的 API key 在哪里获取？

API key 由 Waffo 在商户入网时提供。你可以随时在 **Merchant Portal → Integration**（需要 **Dev** 或 **Admin** 角色）查看。每个 API 请求都要在 `X-API-KEY` 请求头中携带它。沙箱和生产环境使用不同的 API key——上线时要同时切换 API 域名和 key（参见[上线检查清单](/docs/zh/developer-docs/getting-started/go-live)）。

## 我的系统和 Waffo 之间交换哪些密钥？

入网时，你和 Waffo 互换 **RSA 公钥**——各方保留自己的私钥：

| 密钥 | 持有方 | 用途 |
| - | - | - |
| 商户私钥 | 你（仅服务端） | 对你的请求和你的 Webhook 响应签名 |
| 商户公钥 | 由你在 **Merchant Portal → Integration** 配置 | Waffo 用它验证你的签名 |
| Waffo 私钥 | Waffo | 对 Waffo 的响应和 Webhook 通知签名 |
| Waffo 公钥 | 由你从 **Merchant Portal → Integration** 复制 | 你用它验证 Waffo 的签名 |

切勿将私钥发送给 Waffo 或提交到代码仓库。

## 如何对 API 请求签名？

签名算法为 **SHA256WithRSA**。用你的商户 RSA 私钥对请求的**整个 body 报文**签名，并将结果放在 `X-SIGNATURE` 请求头中，与 `X-API-KEY` 一并发送。Waffo 用你在 Portal 配置的商户公钥验签，验签失败则以签名无效错误拒绝请求。所有请求均为 HTTP POST，`Content-Type: application/json`（UTF-8），通过 TLS 1.2 及以上传输。

## 如何验证 Waffo 的 API 响应？

Waffo 用自己的私钥对每个响应 body 签名，并在响应的 `X-SIGNATURE` 中返回签名。在处理响应之前，用 **Waffo 公钥**（来自 Merchant Portal → Integration）以 SHA256WithRSA 验签。如果验签失败：请排查并联系 Waffo，并且**在问题解决前停止发送新交易**——即使你无法接受该响应，Waffo 可能已经处理了你的请求。

## 如何验证 Webhook 通知？

机制与响应相同：每个 Webhook 请求携带 `X-SIGNATURE`，由 Waffo 私钥签名。用 Waffo 公钥验签——对**原始请求 body** 做 SHA256WithRSA（不要先 JSON 解析再重新序列化），签名需先做 Base64 解码——并且务必先验签再处理事件。SDK 的 `handleWebhook()` 会替你完成这一步；完整步骤和 Node.js/Go 示例见
[Webhook signature verification](/docs/zh/developer-docs/webhook/signature-verification)。

## 我回给 Waffo 的 Webhook 响应也要签名吗？

要。你对 Waffo 回调的响应同样携带 `X-SIGNATURE` 请求头，用你的商户私钥对整个 body 报文签名。body 为 `{"message": "success / failed / unknown"}`，按你的处理结果填写。

## A0001 和 A0002 有什么区别？

| 错误码 | 含义 | HTTP 状态 | 指向 |
| - | - | - | - |
| `A0001` | Invalid Api secret key | 401 | 你发送的 `X-API-KEY` 在当前环境无效 |
| `A0002` | Invalid signature | 401 | `X-SIGNATURE` 用你配置的公钥验签失败 |

## 我遇到 A0001，应该检查什么？

1. `X-API-KEY` 请求头存在，且与 **Merchant Portal → Integration** 上显示的 key 一致。
2. 没有把沙箱 key 发到生产域名（或反过来）——每个环境各有自己的 key。

## 我遇到 A0002，应该检查什么？

1. 你签的是**整个 body 报文**——与你实际发送的字节完全一致，而不是重新序列化的副本。
2. 你用的是商户**私钥**，算法为 **SHA256WithRSA**。
3. 在 **Merchant Portal → Integration** 配置的商户**公钥**与该私钥匹配。
4. 上线后使用的是生产环境密钥对——不要复用沙箱预生成的密钥。

## 如何生成 RSA 密钥对？

使用 openssl（[https://www.openssl.org/source），按规范附录给出的方式：](https://www.openssl.org/source），按规范附录给出的方式：)

```bash theme={null}
# generate private key
openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -out merchant_private_key.pem

# generate public key
openssl rsa -in merchant_private_key.pem -pubout > merchant_public_key.pem
```

[上线检查清单](/docs/zh/developer-docs/getting-started/go-live)还说明了如何去掉 PEM 包裹行，得到 Portal 公钥字段所要求的单行 Base64 值。

## 我团队里谁能访问 Integration 页面？

查看 API key 和 Waffo 公钥、配置商户公钥，都需要 Merchant Portal 中的 **Dev** 或 **Admin** 角色。

## 我有多个商户账户，能用一个 API key 通吃吗？

不能。每个 API key 绑定单个商户账户（MID）。用账户 A 的 key 鉴权的请求只能操作账户 A 的数据——用它查询属于账户 B 的订单会失败，即便 key 本身有效。运营多个 MID 时，每个账户保留一套密钥对，并始终用创建该订单的 MID 的 key 调用。

一个相关的查询陷阱：**订阅订单不会通过一次性支付的 Order Inquiry 返回**。请改用订阅专用的查询 API 查询订阅及其支付订单。

## 为什么 SDK 的支付方式查询返回空的 `payMethods` 数组？

通过 SDK 查询你的支付方式配置时，结果中的 `payMethods` 字段始终是空数组——这是预期行为。真实数据在 **`payMethodDetails`** 中：每个已签约支付方式一条，包含 `productName`、`payMethodName`、`country` 和 `currentStatus`（该方式当前是否可用）。遍历 `payMethodDetails` 即可构建各国家下你合约实际启用的支付方式列表。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.