当前已知问题
1 项未修复。 遇到下面这些,不是你的接入姿势错了 —— 不用再排查,按「怎么绕」那一列处理。
我方刻意不做「一切正常」式的状态页: 一个观测不到真实故障的绿灯,比没有状态页更坏 —— 你会拿它当判据。 这一页只声称一件事:我方知道下面这些。
修复后会在变更日志里登记,这一页的条目转成「已修复」并保留一段时间
—— 删掉它等于让照着旧行为写过绕行代码的人无从知道可以拆了。
影响:会员
表现:用已属其他商户的 email / 手机号建会员会返回 400 invalid_request
(不是 409 —— 我方不下发「这个人已经存在」这种可被用来探测的信息)。
怎么绕:目前无法绕过,身份层的唯一索引尚未按商户拆分。 如果你的用户群与其他 Zise 商户有重叠,请提前告知你的客户经理。
api_error,而不是 4xx影响:兑换 · 站内转账 · 理财 · 扫码付 · 汇款 · 发卡 · 提现地址
表现:「余额不足」「报价过期」「该方向未启用」「地址校验和不对」这类合法的业务拒绝,
对外呈现成 500 api_error,而不是带明确 code 的 4xx。
成因是内部码没登记进对外码目录,走了缺省分支。
2026-08-12 已修复。 这些拒绝现在返回带明确 code 的 4xx。
如果你之前为此写过「对 500 设重试上限」的绕行代码,可以拆了 ——
但保留一个上限总是对的,upstream_timeout(504) 之外的 5xx 不该无限重。
同时新增了守卫 tools/check-open-error-codes.mjs:内部码没登记、
或登记了却零发射点,提交期就红。
影响:GET /v1/cards/{id}/transactions · GET /v1/earn/products/{id} · POST /v1/cards/{id}/replacements
表现:前两个选了不存在的列;第三个漏了 reason 白名单,任意字符串会撞库级约束。
已修复。 修的过程里还抓到第四个同类:GET /v1/cards/{id} 选的
balance_micro 在全部 127 个迁移里一次都没出现过(真名 upstream_balance)——
它同时是卡详情的全部内容、也是流水端点的门,所以流水就算列名全对也进不去。
卡消费流水现在多了一个 direction 出参:amount 是绝对值,
只看金额的话一笔退款与一笔消费长得一模一样。
GET /v1/remittances/{id} 会回显内部状态,且金额格式与列表不一致影响:汇款
表现:详情端点可能返回 pending_merchant_funds(列表与下单口都会折叠成 pending);
同一笔单的 source_amount 在详情里是未插小数点的定点整数串,
在列表里是十进制串 —— 两者差 10^ledger_scale 倍,而两边都返回 200。
已修复。 三个出口(下单 / 列表 / 详情)现在走同一个映射函数,
不是三份各自的三元表达式 —— 后者正是这类泄漏复发的成因。
金额统一走十进制串并随行下发 ledger_scale。
status_version 恒为 0(其中 2 条是缺陷,7 条是设计如此)影响:Webhook
表现:事件目录里逐条标注了。受影响的事件里,status_version 不随状态变更递增。
2026-08-13 处理完毕。 这一条原本记成一个问题,实际是两件事:
① 真缺陷,2 条,已修: card.application.approved 与 card.status.updated。
它们的 data.id 发的是会员内部 id(而 data.object 写着
card_application / card)—— 你拿它回查必然 404。版本号读不出来是同一个
成因的副产品:我方按 data.id 所属的那张表去读版本,而根本没拿到那张表。
现在两条都发真实单号(申请单号 / 卡 id)并带真实版本号。
⚠ 如果你的 handler 里写着「卡这两条的 id 是会员 id」,请改回常规约定。
② 不是缺陷,7 条,保持原样并写明了原因: member.created /
member.suspended / kyc.result.updated / deposit.credited /
exchange.order.executed / transfer.completed /
earn.order.settled(仅活期派息那一半)。
它们的对象要么根本没有状态机(入金只有「已入账」一态、兑换与转账原子成交),
要么根本不是一张单(KYC 的对象是人,活期是余额包)。
给它们造一个版本号不会让任何东西变得更可靠。
上面那条绕行办法对这 7 条继续有效,请照做。
顺带删掉了 data.previous_status:它恒为空串、一个生产者都没有。
理由与不「补上真值」的原因见 Webhook 指南。
我方侧新增了守卫 tools/check-webhook-route.mjs(提交期):通知调用点没告诉
桥接「这条通知指向哪一单」时直接红。此前那是个静默兜底 —— 事件照发、
签名正确、你的端点回 2xx,只有你回查那一下会 404。
影响:沙盒
表现:注入 timeout / unknown / unknown_status 会返回 200 并回显你设的值,
但后续每一单仍然打真实上游、用真实凭据 —— 那个设置从来没有被任何
业务代码读过。
已修复。 四条业务线的上游客户端都在
最底层那一跳 fetch 上接了注入层,作用域由 merchantAuth 装配
(判据是「打的是沙盒域名」且「解析到的是影子主体」两条同时成立)。
两处刻意的设计,用法见沙盒指南:
· 只替换动钱的那一跳 —— 同一家上游的报价/解码/查询照常打真实上游。
全部替换的话订单会在锁钱之前就干净地失败,而你真正要测的
「钱可能已经放行了」那一支永远走不到;
· 注入的是上游的响应,不是订单状态 —— 我方拿到之后照生产上逐字
相同的分类、重试、留痕、状态机去处置。所以你在沙盒里看到的,
就是同一件事在生产上会有的样子。
GET /v1/balances 的响应信封与其余清单端点不同影响:余额
表现:它返回 { balances: [...] },而其余清单端点是 { data, next_cursor, has_more }。
2026-08-13 已修复。 该端点现在返回标准信封 { data, next_cursor, has_more }
(不分页,所以 next_cursor 恒为 null、has_more 恒为 false)——
你的通用翻页器不用再为它单独分支。
⚠ balances 没有被删,它仍然返回,且与 data 指向同一份数组。
这是过渡期兼容字段:直接换成 data 的话,已经按 balances 接完的
调用方会在我方部署的那一刻静默读到 undefined —— 不是报错,是
「所有余额凭空消失」,而多数界面会把它画成 0。
所以请照这个顺序做:新接入一律读 data;已经读 balances 的择期改过来。
移除 balances 会提前在变更日志里预告,届时不再有第二次兼容。