> ## 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.

# 常见错误排查

> 如何诊断和修复商户最常遇到的 API 错误——无效 API key（A0001）、签名失败（A0002）、参数校验（A0003）、支付方式/合约不匹配（A0018）、未知状态错误（Exxxxx），以及不断重试的 webhook 通知。

每个失败的 API 调用都会在响应体中返回 `code` 和 `msg`。码的首字母告诉你谁需要采取行动：

| 前缀 | 类别 | 谁来处理 |
| - | - | - |
| `A`xxxxx | 商户相关错误 | 修正你的请求或配置，然后重新发送 |
| `B`xxxxx | 用户相关错误 | 引导用户（余额、超时、授权） |
| `C`xxxxx | 系统相关错误 | Waffo 侧的瞬时问题——稍后重试或联系客服 |
| `D`xxxxx | 风控相关拒绝 | 被风控拦截；如非预期请联系客服 |
| `E`xxxxx | 未知错误 | 持续查询直到得到最终的 Success/Failed 状态 |

完整列表见 [错误码速查](/docs/zh/developer-docs/tools-and-references/developer-tools/error-codes)。本页覆盖产生最多客服工单的那些码。

## 我收到 `A0001` "Invalid Api secret key"——API key 从哪里来？

`X-API-KEY` 请求头缺失，或者与签发给你账户的 key 不匹配。API key 由 Waffo 在商户入网时提供，并可在商户 Portal 的看板中查看。

常见原因：

1. **环境不匹配**——沙箱和生产使用**不同的 API key 和 RSA 密钥**。把沙箱 key 发到 `https://api.waffo.com`（或把生产 key 发到 `https://api-sandbox.waffo.com`）会以 `A0001` 失败。
2. 请求中完全缺少 `X-API-KEY` 请求头。

修复：从商户 Portal 复制目标环境的 key，并确认 base URL 与该环境匹配。见 [沙箱与测试](/docs/zh/developer-docs/getting-started/sandbox)。

## 我如何调试 `A0002` "Invalid signature"？

Waffo 使用 **SHA256WithRSA**，用**你在入网时交换的商户公钥**验证 `X-SIGNATURE` 请求头。验证失败意味着你生成的签名与 Waffo 收到的请求体不匹配。请按以下清单逐项排查：

1. 对**与传输内容完全一致的原始请求体字符串**签名——不要先 JSON 解析再重新序列化，也不要对美化过或重新排序过的副本签名。
2. 确认你使用的**私钥对应的公钥已在 Waffo 注册**且属于当前环境（沙箱和生产的 RSA 密钥是分开的）。
3. 确认算法是 `SHA256WithRSA`。
4. 如果你生成了新的密钥对，新公钥必须先在 Waffo 注册，然后才能切换。

反方向同样重要：Waffo 用自己的私钥对每个响应和 webhook 签名，你用 Waffo 公钥验证（商户 Portal → **Integration** 菜单）。**如果你对 Waffo 响应的验证失败，请停止发送新交易并联系 Waffo**——即使你无法信任该响应，你的原始请求也可能已经被处理。代码示例：[webhook 签名验证](/docs/zh/developer-docs/webhook/signature-verification)。

## 通常是什么触发 `A0003` "Parameter validation failed"？

`A0003` 是请求格式被拒绝。`msg` 字段携带详情；生产客服中最高频的原因有：

1. **字段长度超限。** 每个字符串字段都有声明的最大长度——商户在 `/api/v1/order/create` 上最常超限的字段：

   | 字段 | 最大长度 |
   | - | - |
   | `paymentRequestId` | String(32) |
   | `merchantOrderId` | String(64) |
   | `orderDescription` | String(128) |
   | `userEmail` | String(64) |
   | `userPhone` | String(16) |
   | `goodsName` | String(64) |
   | `goodsUrl` | String(128) |
   | `appName` | String(32) |
   | `notifyUrl` | String(256) |

2. **金额格式。** 金额是最多 2 位小数的字符串——并且**像 `JPY` 这样的零小数币种必须是整数**。一个真实的生产示例：`"orderCurrency":"JPY","orderAmount":"200.88"` 会以 `A0003` 被拒绝；`"201"` 则被接受。见 [币种处理](/docs/zh/developer-docs/core-concepts/currency)。

3. **格式约定**——时间为带毫秒的 ISO 8601（`2023-04-01T03:00:00.000Z`），币种为 ISO 4217，国家为 ISO 3166-1 alpha-3（`IDN`、`PHL`），`userPhone` 遵循 `+CountryCode-Number`，例如 `+62-08990013157`。

发送前请在本地校验这些内容；每个字段的精确契约见 [Acquiring API Specification](/docs/api-reference/introduction)。

## `A0018` 是什么意思，怎么修复？

在收单 API 中，`A0018` 是 **"Payment method in merchant order does not match with current merchant contract"**——你订单中的 `payMethod`/国家/产品组合不是你已签约的组合。

修复方法：

1. 调用 `/api/v1/paymethodconfig/inquiry`。响应会列出每个已签约的支付方式及其 `productName`（`ONE_TIME_PAYMENT` / `DIRECT_PAYMENT`）、`payMethodName`、`country` 和 `currentStatus`（`1` 可用，`0` 不可用），以及任何 `fixedMaintenanceRules` 窗口。
2. 只发送出现在该列表中且 `currentStatus` 为 `1` 的组合。你能签约哪些支付方式取决于你的合约配置——查看商户 Portal 或联系集成支持来添加。
3. 两个相邻的码看起来相似，但它们要求的是更精确的信息，而不是合约变更：`A0022`（请指定 `productName`——找到多个产品）和 `A0033`（请指定支付方式国家——找到多个支付方式）。

注意：同一个码在**订阅** API 中被复用，那里它表示该用户没有可用的支付方式继续扣款（例如，用户已没有可用的已绑定支付方式）。错误文本相同；只是情形不同，所以要结合你调用的 API 一起解读。

## 我的合约覆盖了该支付方式——为什么传 `userCurrency` 时仍然收到 `A0018`？

`A0018` 也会在**货币对维度**触发。`orderCurrency` → `userCurrency` 组合（展示货币对）必须在你的合约中启用，独立于支付方式本身。例如，`orderCurrency=JPY` 且 `userCurrency=USD` 的订单会以 `A0018` 被拒绝，除非 JPY→USD 货币对已签约——即便卡支付已签约也一样。

两条出路：

1. **省略 `userCurrency`。** Waffo 收银台随后会按当前汇率自动把订单金额换算为用户的本地币种。
2. **启用该货币对。** 如果你需要自己固定面向用户的币种，请联系你的 Waffo 集成支持把该货币对加入合约。

## 我的订单因为金额被拒绝了。限额在哪里查？

每个支付方式对每种币种都有自己的最小和最大订单金额，有些组合在常规币种规则之上还带有精度规则（零小数币种必须是整数，少数支付方式接受的小数位数少于币种通常允许的位数）。超出范围或精度的金额会在创建订单时以明确的错误被拒绝。

你可以通过程序读取限额：`/api/v1/paymethodconfig/inquiry`
会为每个已签约支付方式返回 `orderAmountMin` 和 `orderAmountMax`，
并附带其 `currency`。注意响应是每个合约一条记录，
而不是每个支付方式一条，所以同一支付方式可能以不同币种、不同限额出现多次——
请按你要收款的币种匹配。商户 Portal 展示同样的配置。

限额是**依赖合约的固定值**：它们在支付方式为你的账户签约时设定，不会随汇率变动——跨币种订单也一样。要找到适用于你的值，请查看商户 Portal 中的支付方式配置，或询问你的 Waffo 集成联系人。

## 我收到 `E0001` "Unknown status"。支付失败了吗？

没有——未知不是终态。`E`xxxxx 错误意味着结果在 Waffo 内部或第三方系统中尚未确定。把该交易视为**处理中**，持续查询（`/api/v1/order/inquiry`）直到收到最终的 Success/Failed 状态。绝不要仅凭 `E` 码就向用户显示失败或重新扣款。

重试原始请求时，复用相同的 `paymentRequestId`——它是幂等键。用**不同**参数复用它会以 `A0011` "Idempotent param mismatch error" 失败。见 [幂等性](/docs/zh/developer-docs/core-concepts/idempotency)。

## Waffo 一直给我发同一条通知。为什么？

你的端点没有确认它。一个反复出现的客服案例：某商户的 webhook 端点回复了 `Content-Type: application/octet-stream` 和 `{"message":"fail"}`——于是 Waffo 持续重新投递该通知。要确认收到：

1. 以 `Content-Type: application/json` 响应。
2. 在处理完事件后以请求体 `{"message":"success"}` 响应。任何 `failed` / `unknown` 回复、非 200 状态、超时或无法解析的请求体都会触发重试计划——见 [webhook 重试](/docs/zh/developer-docs/webhook/retry)。
3. 让你的处理程序幂等：重试意味着同一事件可能到达不止一次。


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