Z Zise Developers

当前已知问题

1 项未修复。 遇到下面这些,不是你的接入姿势错了 —— 不用再排查,按「怎么绕」那一列处理。

我方刻意不做「一切正常」式的状态页: 一个观测不到真实故障的绿灯,比没有状态页更坏 —— 你会拿它当判据。 这一页只声称一件事:我方知道下面这些。

修复后会在变更日志里登记,这一页的条目转成「已修复」并保留一段时间

—— 删掉它等于让照着旧行为写过绕行代码的人无从知道可以拆了。

未修复同一自然人不能在两个商户下各建一个账号

影响:会员

表现:用已属其他商户的 email / 手机号建会员会返回 400 invalid_request (不是 409 —— 我方不下发「这个人已经存在」这种可被用来探测的信息)。

怎么绕:目前无法绕过,身份层的唯一索引尚未按商户拆分。 如果你的用户群与其他 Zise 商户有重叠,请提前告知你的客户经理。

已修复一部分业务拒绝返回 500 api_error,而不是 4xx

影响:兑换 · 站内转账 · 理财 · 扫码付 · 汇款 · 发卡 · 提现地址

表现:「余额不足」「报价过期」「该方向未启用」「地址校验和不对」这类合法的业务拒绝, 对外呈现成 500 api_error,而不是带明确 code 的 4xx。 成因是内部码没登记进对外码目录,走了缺省分支。

2026-08-12 已修复。 这些拒绝现在返回带明确 code 的 4xx。

如果你之前为此写过「对 500 设重试上限」的绕行代码,可以拆了 ——

保留一个上限总是对的upstream_timeout(504) 之外的 5xx 不该无限重。

同时新增了守卫 tools/check-open-error-codes.mjs:内部码没登记、

或登记了却零发射点,提交期就红。

已修复三个端点一调用就 500

影响: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

已修复9 条事件的 status_version 恒为 0(其中 2 条是缺陷,7 条是设计如此)

影响:Webhook

表现:事件目录里逐条标注了。受影响的事件里,status_version 不随状态变更递增。

2026-08-13 处理完毕。 这一条原本记成一个问题,实际是两件事:

① 真缺陷,2 条,已修: card.application.approvedcard.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 恒为 nullhas_more 恒为 false)——

你的通用翻页器不用再为它单独分支。

balances 没有被删,它仍然返回,且与 data 指向同一份数组

这是过渡期兼容字段:直接换成 data 的话,已经按 balances 接完的

调用方会在我方部署的那一刻静默读到 undefined —— 不是报错,是

「所有余额凭空消失」,而多数界面会把它画成 0。

所以请照这个顺序做:新接入一律读 data;已经读 balances 的择期改过来。

移除 balances 会提前在变更日志里预告,届时不再有第二次兼容。