跳到正文

API

本页内容

错误码

用稳定的机器可读错误码处理 Merchant API 失败,含字段级校验明细和文档化的恢复路径。

错误码目录

code 中(以及逐字段在 errors[].code 中)返回的稳定机器可读标识符。这是当前在线集合——以下每个错误码都至少由运行中的 API 的一个处理器、校验器或中间件产生,不是理论上的超集。已有错误码的语义永不改变,新错误码随新场景加入。改名只在极少数情况下发生,每次都会在更新日志中公布。

程序化判断用 codedetail 仅英文,供日志/兜底 UI 使用;客户端按 code 做本地化。

字段级错误码

由请求校验发出。以下每个错误码都会把 field 设为出错字段的 snake_case 名称。当多个字段同时出错时,顶层 codevalidation_failed,每个字段的失败明细进入 errors[]

错误码 何时出现 处理方式
validation_failed 多个字段同时出错时的顶层 code。每个字段的失败在 errors[] 中携带自己的 codefield 检查 errors[],逐一修复列出的 field
field_required 必填字段为空、为 null 或只有空白字符。 field 提供值。
field_too_long 字段超过允许的最大长度。 截断到该端点文档说明的上限。
field_out_of_range 数值超出允许范围。 将数值收敛到文档说明的范围。
field_invalid_enum 值不在接受的枚举成员中(如未知的 currency / network,或项目未启用的代币)。 查阅枚举参考;对于代币,确认项目已启用该代币+网络组合。
field_invalid_format 值不符合字段期望的形态——无法解析的 id(如缺少 inv_… 前缀的 invoice_id),或不是 "10.00" 这类普通十进制字符串的 amount 按文档格式发送字段;原样使用 API 返回的 id。
entity_id_empty 提供的 id 是全零/空 GUID(00000000-0000-…)。field 指出错的 id——如 invoice_idwithdrawal_id 原样发送 API 返回的 id;绝不要发送全零或空 id。
field_must_be_positive 十进制/整数必须大于 0。 发送正值。
field_percentage_out_of_range 百分比必须在 0 到 100(含)之间。 将值收敛到 [0, 100]
query_parameter_unknown 列表请求中包含该端点不支持的查询参数。 移除该参数,或改用文档说明的 snake_case 名称。
pagination_cursor_invalid 游标格式错误、已过期、被篡改、属于其他资源,或与不同的过滤条件组合使用。 不带 cursor 重新开始分页,然后跟随 next_cursor 时保持相同的过滤条件。
amount_too_many_decimals 对于法币流程的账单,amount 的小数位数超过该币种的最小单位(如 USD23.345JPY23.01)。 按币种最小单位取整。
amount_too_large 创建账单或转出时的 amount 超出支持范围——高于 API 存储的 20 位整数上限。 发送支持范围内的金额。

通用 HTTP 状态兜底码

当失败没有附带具体业务错误码时返回。每一项都是某个 HTTP 状态的兜底:请求失败了,但没有更细粒度的错误码描述原因。

错误码 HTTP 何时出现 处理方式
forbidden 403 已认证,但该凭证无权执行此操作——其作用域(能力)或环境不允许,例如用 Sandbox 密钥调用仅正式环境可用的端点。 改用能力与环境都匹配该操作的凭证。归属问题永远不会是 403:属于其他商户的资源返回 not_found(404),而不是 forbidden
payment_key_required 403 端点需要 Payment(pk_)密钥,但请求使用的是 Payout(rk_)密钥——例如列出账单。 改用 Payment 密钥调用。
payout_key_required 403 端点需要 Payout(rk_)密钥,但请求使用的是 Payment(pk_)密钥——例如查询余额。 改用 Payout 密钥调用。注意 Payout 密钥还需先配置 IP 白名单才能使用。
internal_error 500 我们这边的意外错误或 bug。 重试一次。若持续失败,联系支持并附上响应发生的时间。
validation_failed 400 请求未通过校验,但没有单一字段级错误码适用。 读取 detail 字段——里面说明了被拒绝的内容。

认证

仅由 HMAC 认证处理器在 401 Unauthorized 响应中返回。每个错误码定位一个具体的失败点,让客户端能给出可操作的提示,而不是笼统的「认证失败」。

错误码 HTTP 何时出现 处理方式
unauthorized 401 通用兜底:以下具体错误码均不适用时——通常是向需要认证的端点发请求但没有 Authorization 请求头(或认证方案无法识别)。 发送合法的 HMAC Authorization 请求头;端到端复查签名流程。
authorization_missing 401 Authorization 请求头的值为空(发送了但为空白)。 发送完整的 Authorization: HMAC-SHA256 {apiKeyId}:{base64signature} 请求头。
authorization_malformed 401 请求头存在但格式错误:scheme 能解析,但凭证部分缺少冒号、API key ID 无法解析,或签名为空。 身份认证重新构造请求头;最常见的原因是 API key ID 中有拼写错误。
timestamp_missing 401 缺少 X-Request-Timestamp 请求头,或其值无法解析为正整数。 将该请求头设为当前 Unix 时间戳(秒)。
timestamp_expired 401 时间戳超出允许的时钟偏差窗口(默认 5 分钟)。 用 NTP 校准时钟;用新的时间戳重新签名。
invalid_credentials 401 凭证不可用:key ID 未知、密钥已吊销、环境/类型前缀与存储的密钥不匹配,或签名校验失败。四种情况刻意共用一个错误码——如果给出可区分的回答,等于向不持有 secret 的调用方确认哪些 key ID 存在。 检查 API key ID 是否正确且处于活跃状态,签名是否用匹配的 secret 计算。签名是最常见的原因:核对你的 string-to-sign 拼装({ts}\n{METHOD}\n{path}\n{query}\n{bodyHash}),并确认空请求体时 bodyHash 为空(不要对空字符串做哈希)。
ip_not_allowed 401 Payout 密钥配置了 IP 白名单,而你的调用方 IP 不在其中。只有 Payout 密钥有 IP 检查——Payment 密钥可从任意 IP 调用。该检查在签名通过之后才执行,因此来自错误网络的合法签名同样会失败。 在控制台中将调用方 IP(或其 CIDR 段)加入该 Payout 密钥的白名单。
payout_whitelist_required 401 新生成的 Payout 密钥尚未配置 IP 白名单。Payout 密钥在商户添加至少一个允许的 IP 之前保持不可用——与 ip_not_allowed 区分开,便于客户端分辨「控制台未配置」和「来源 IP 不对」。 打开控制台的 API 密钥页面,在该 Payout 密钥的 IP 白名单中配置至少一个 IP 或 CIDR。

限流

当请求超过商户限流时,以 429 Too Many Requests 返回。计数以商户为单位,按一秒窗口进行,密钥不单独计算:你的所有 API 密钥合用一份额度。在 API 之前,还有一层按 IP 地址计数的限流;本页说明的是商户这一层。

错误码 HTTP 何时出现 处理方式
rate_limited 429 超过按商户计算的限流。有两条限制:所有端点的全局限额(默认 30 次/秒),以及账单创建 POST /v1/invoices 的更严格限额(默认 5 次/秒)。响应会说明触发了哪条以及限额是多少。 读取 Retry-After 请求头(退避秒数),到时后重试;大多数带重试中间件的 HTTP 客户端会自动遵守。

传输/框架

当请求根本没有到达常规处理器时,由框架错误处理器返回。

错误码 HTTP 何时出现 处理方式
malformed_request 400 请求体无法解析——JSON 格式错误。 确认请求体是合法的 JSON。
payload_too_large 413 请求体超过 1 MiB 限制。 发送更小的载荷;把大批量任务拆成多个请求。
unsupported_media_type 415 Content-Type 不是 application/json 设置 Content-Type: application/json
method_not_allowed 405 路径存在,但不支持此 HTTP 方法。 使用端点文档说明的方法(如用 POST 创建)。
route_not_found 404 没有端点匹配该请求路径。 对照 API 参考重新核对 URL。

账单

错误码 HTTP 何时出现 处理方式
invoice_not_found 404 账单 id 解析不到任何记录,或解析到属于其他商户的账单。 原样使用 POST /v1/invoices 返回的 id。
project_not_found 404 创建账单请求中的 project_id 解析不到调用方可见的任何项目。 使用控制台中的项目 id(必须为活跃状态,且与 API 密钥属于同一商户)。
invoice_terminal 410 对已处于 expiredcancelled 的账单调用了 confirm-payment。(paid 账单返回的是 invoice_not_awaiting_client,409——不是本错误码。) 刷新账单状态;无需再做其他操作。
invoice_deadline_passed 410 在账单截止时间之后调用了 confirm-payment。 创建新账单。
requested_amount_invalid 400 账单的 amount 缺失、格式错误、超出支持的十进制范围,或不为正数。 以正的十进制字符串发送 amount,并携带所选的 currency 和可选的 network
invoice_amount_below_minimum 400 账单折算后的 USD 价值低于目录中该代币/网络的最低限额。 将金额提高到所选代币展示的最低限额以上。
deposit_amount_exceeds_limit 400 预期付款折算后的 USD 价值超过商户每笔充值的 MaxDepositAmount 策略上限。约束的是确认时的报价金额,而非实际链上到账。 降低账单金额,或联系支持提高限额。
currency_not_enabled_for_project 400 请求的加密货币不在项目的已启用代币列表中(任意网络)。 在项目上启用该币种,或从项目的 enabled_tokens 中选择。
tokens_required 409 在一个完全没有启用代币的项目上创建账单或确认付款。 在控制台中为该项目启用至少一个代币。
acceptance_disabled 503 所请求的代币目前不接受收款。 改用其他代币,或稍后重试。
exchange_rate_unavailable 503 汇率提供方没有该代币/法币对的新鲜报价。 重试;汇率以短间隔刷新。
network_unavailable 503 自动确认无法使用所选网络。 放弃自动确认;让客户通过托管页面选择代币。
payment_method_unavailable 503 所选代币或网络当前无法接收付款。自 2026-08-23 起取代 no_available_addressaddress_lease_failedbridge_unavailable 重试,或让客户改选其他代币或网络。
client_confirmation_failed 409 客户端确认(代币选择、自动确认)被拒绝。detail 字段包含具体原因。 检查 detail;常见情况:账单已过 awaiting_client 状态、代币不被允许。
invoice_not_awaiting_client 409 对不再处于 awaiting_client 的账单调用了 confirm-payment。 刷新账单状态;客户已完成选择。
invoice_cannot_be_cancelled 409 账单不再处于 awaiting_client——客户已选择代币,或账单已支付或已过期。对已经取消的账单再次取消返回 200,而不是本错误。 检查当前状态;只有 awaiting_client 状态下才能取消。
simulate_payment_failed 409 仅 sandbox 可用的 simulate_payment 被拒绝。 检查 detail;通常是状态不对或金额不匹配。
not_sandbox 403 对正式账单调用了 simulate-payment(sandbox 模拟器)。 只有 sandbox 账单可以模拟——改用 sandbox 账单,或用真实的链上付款驱动正式账单。

Widget 账单

POST /public/v1/sdk(Low-Code SDK 账单创建)返回。

错误码 HTTP 何时出现 处理方式
widget_key_missing 401 在需要 widget 认证的端点上缺少 X-Sdk-Key 请求头或其值为空。 X-Sdk-Key 中发送公开 SDK 密钥。
widget_key_invalid 401 X-Sdk-Key 存在,但无法解析为 Paymos API key ID。 从控制台复制密钥;检查是否有多余空白、错误前缀或意外的 URL 编码。
widget_key_not_found 401 密钥能解析,但解析不到活跃凭证——已吊销、已删除,或不是 Payment 类型的密钥(Payout 密钥无法驱动 widget)。 使用控制台中处于已启用状态的 Payment 密钥。
widget_inactive 403 目标项目的 widget 已关闭,或该项目的 widget 从未初始化。 在项目设置中启用 widget。
terminal_not_enabled 403 请求携带 source=terminal,但项目的集成方式不是「收银终端」。 新建收银终端类型的项目,或从 Low-Code 项目发送 source=embed
embed_not_enabled 403 请求携带 source=embed,但项目的集成方式不是「Low-Code」。 使用项目自身的集成方式,或新建 Low-Code 项目。
origin_not_allowed 401 浏览器 Origin 不匹配允许来源策略。该检查执行两次——认证层把 origin 与该密钥下所有启用 widget 的项目取并集匹配,处理器再与精确的目标项目匹配——两次都回同一个 401、同一个错误码、同一段 detail。这是刻意的:第二次检查若换个状态码,就等于告诉持有那把公开可抓取的 pk_ 密钥的调用方,这个 origin 注册在同一商户的另一个项目下,测试域名和未发布的品牌可以被一次一次探出来。 把域名加入 widget 的允许来源。同源请求——例如从同一主机提供服务的 POS 终端——跳过该检查。

收款通道

错误码 HTTP 何时出现 处理方式
payment_channels_disabled 503 本环境下你的账户未开通收款通道。所有通道和充值接口都返回它,沙箱模拟器也不例外。 联系支持开通。重试不会改变结果。
payment_channel_not_found 404 pc_ id 解析不到该凭证可以看到的任何东西——不存在、属于其他商户、在另一个环境,或位于 key 作用域之外的项目。四种情况刻意无法区分。 原样使用 POST /v1/payment-channels 返回的 id,并用同环境同项目的 key 签名。
payment_channel_deposit_not_found 404 pcd_ id 解析不到该凭证可以看到的任何东西。与上面同样的四种原因。 原样使用 webhook 载荷或轮询流中的 id。
payment_channel_external_id_invalid 400 external_id 为空、全是空白,或超过 128 字符——创建时和作为列表筛选条件时都算。 发送非空白、最长 128 字符的标识。
payment_channel_project_has_no_supported_tokens 409 项目没有启用任何收款通道可收的代币,通道将完全没有路线。 先在项目上启用至少一个受支持的代币,再创建通道。
payment_channel_simulation_sandbox_only 403 对正式通道调用了 simulate-deposit 模拟只对沙箱通道存在。正式通道请用真实转账驱动。
payment_key_required 403 请求用 Payout(rk_)key 签名。通道访问走 Payment key,正如转出走 Payout key。 用同环境的 pk_ key 签名。
pagination_cursor_invalid 400 列表或数据流游标格式错误、超过 24 小时,或绑定了不同的筛选条件——对数据流来说,还包括不同的商户、环境或项目作用域。 从第一页重新开始。按 pcd_ 去重让整轮重新同步无害。
currency_not_enabled_for_project 400 传给 simulate-deposit 的代币不在项目的已启用代币列表中。 在项目上启用它,或改用通道 networks[].tokens 里已经返回的代币。
acceptance_disabled 503 所请求代币的收款目前在平台级被停用。 改用其他代币,或等待收款重新启用。
amount_too_many_decimals 400 模拟金额的小数位超过该代币支持的位数。商户的钱绝不会被悄悄舍入成另一个数。 发送前把金额舍入到该代币的精度。

转出

错误码 HTTP 何时出现 处理方式
withdrawal_not_found 404 转出 id 解析不到任何记录,或解析到属于其他商户的转出。 原样使用 POST /v1/withdrawals 返回的 id。
insufficient_balance 409 商户可用余额低于 amount + fee 充值,或降低转出金额。
whitelist_required 403 目标地址未列入所选网络的白名单。(该网络支持白名单;这个具体地址尚未添加。) 把地址加入白名单后重试。
destination_address_invalid 400 地址未通过该网络的格式/校验和验证。 对照网络规范重新核对地址。
withdrawal_amount_below_minimum 400 金额低于所选代币的策略最低限额。 将金额提高到最低限额以上(在 detail 中返回)。
withdrawal_quota_exceeded 409 进行中的转出数量达到商户策略上限。 等待在途转出结算完成,或联系支持提高限额。
withdrawal_amount_exceeds_limit 400 转出本金的 USD 等值超过商户每笔交易的 MaxWithdrawalAmount 策略上限。 降低金额,或联系支持提高限额。
exchange_rate_unavailable 503 商户设置了 MaxWithdrawalAmount 上限,但没有新鲜的代币/USD 报价可用于核对本金——限额无法验证,因此请求按失败关闭处理。 重试;汇率以短间隔刷新。
withdrawal_not_enabled 400 Paymos 不支持你请求的代币/网络组合的转出。detail 会指明该组合——如 Withdrawals are not available for USDT on TRC20. 哪些组合可转出由我们的配置决定,不由商户决定。 改用 Paymos 支持转出的网络,或联系支持询问你需要的组合。
withdrawal_cannot_be_cancelled 409 转出已越过可取消的状态。 检查当前状态。执行一开始,窗口就关闭——那时仍在 created,还没有任何签名。
withdrawal_simulation_failed 409 仅 sandbox 可用的 simulate_completion 被拒绝。 检查 detail
merchant_suspended 403 商户账户的转出流程已被暂停,无法创建转出。 联系支持解除暂停。
outbound_frozen 503 转出被冻结——可能是平台级,也可能只针对你这笔转出所用的特定网络和代币。 等待冻结解除,换用其他网络/代币,或联系支持。
withdrawal_network_unavailable 503 该代币在此网络上的转出目前无法完成。 换用其他目标网络,或稍后重试。

项目状态

当项目在当前状态下无法开具账单时,由账单创建和付款确认返回。

错误码 HTTP 何时出现 处理方式
project_state_invalid 409 项目不是 Active——处于 SuspendedArchived。响应不会说明是哪一种。 在控制台查看项目状态:已归档则恢复,已暂停则激活。或者把请求发给一个已处于活跃状态的项目。