Z Zise Developers

变更日志

每条都标注了「是否需要你动手」。 标「需要」的,不做会在某一天出问题;

标「不需要」的是纯增量,你不改代码也不会坏。

我方对枚举值的承诺:新增状态值会提前在这里登记。所以你的 default

分支应当按「未知」处理并告警,而不是假装认识它 —— 见各端点页的状态说明。

这份变更日志从 2026-08-12 开始维护。在此之前的变更没有逐条记录。

network 统一成机读码;GET /v1/assets 补出网络清单;quote_id 不再被静默忽略 需要你动手

需要你动手(第 ① 条是破坏性变更)。

GET /v1/merchant/deposit-addressesnetwork 改成机读码。

此前它出的是展示名BNB Smart Chain (BEP20)),而同一资源的

POST 收的是机读码BSC)—— 把 GET 回给你的值原样回传给 POST

必然 asset_not_allowed。这是一个自相矛盾的契约,现在两边同口径:

network 一律是机读码,展示名改走新增的 network_name

如果你的代码里存过这个字段并拿它做过展示,请改读 network_name

如果你曾经为此硬编码过一张映射表,可以删掉了。

② 本页此前把 BSC 的机读码写成 BEP20 —— 那个值不存在。

正确值是 BSCBEP20 只出现在展示名里。照旧文档传 BEP20 会被拒。

GET /v1/assets 现在逐资产给出 networks[]

这是机读码的唯一权威清单,也补上了此前完全拿不到的那些数:

逐网络的 deposit_enabled / withdraw_enabled(不可用的也列出并给原因)、

min_deposit / confirmations_required / memo_required

提现侧的 min_withdraw / max_withdraw / withdraw_fee_* /

withdraw_cooling_hours / withdraw_eta_minutes

请不要再把网络清单写死在代码里 —— 加币种是我方后台加一行、不发版,

写死的那份不会跟着变。

④ 会员兑换的锁价现在是真的了 —— quote_id 可用。

POST /v1/exchange/quoteslock: true 拿回 quote_id

POST /v1/exchange/orders 带上它就按那份报价成交;过期一律拒,

绝不回落成按新价成交。quote_id 就是这一单的订单号,

成交请求超时时直接 GET /v1/exchange/orders/{quote_id} 就能查成没成。

锁价要显式索取lock 缺省 false)。两条理由:这个端点会被当成

「给界面显示一个数」高频调用,无条件建单会把你的订单清单灌满从未成交的

quoted 行;而一份锁定的报价对你就是一个 quote_ttl_sec 秒的免费期权,

所以要就显式要,每一次都是一行可数、可审计的记录。

锁的是价,不是授权 —— 成交那一刻照样跑全部闸(账户处置、方向停用、

强认证、限额、余额)。没锁价时 quote_ttl_sec 仍然只是参考值。

背景(这条修的是我方的一次前后矛盾):接口注释一度写着「想锁价的商户……

下单时再传 quote_id」,而 quotes 从来不返回 id、orders 也从来不读它 ——

照那句话写的代码以为自己锁了价,实际按成交那一刻的新价成交,

差额自己吃且全程零提示。中途曾短暂改成「传了当场拒

quote_lock_unsupported)」,现在能力补齐,那条码在会员兑换上不再出现

它今天唯一的适用处是商户自兑换POST /v1/merchant/conversions

那条线还没有锁价)。

卡两条事件的 data.id 改成真实单号;previous_status 删除 需要你动手

需要你动手(两处都很小,但不改会在某一天出问题):

card.application.approvedcard.status.updateddata.id

此前它们发的是会员内部 id,而 data.object 写着 card_application /

card —— 拿它回查必然 404。现在发真实单号:申请单号(回查

GET /v1/cards/applications/cap_<id>)与卡 id(回查 GET /v1/cards/crd_<id>)。

如果你的 handler 里写过「卡这两条的 id 是会员 id」的特例,请拆掉。

这两条同时开始带真实 status_version —— 卡状态会连着来两条

freezingfrozen),请按版本号向前合并

② 事件体里不再有 previous_status 它一直恒为空串(一个生产者都没有)。

如果你写过 if (data.previous_status === …),那条分支从来没有成立过;

请改用你自己库里的当前值。我方不会补上真值 —— 同一次状态变更重复到达是

常态,第二次到达时「上一个状态」已经等于新状态,一个错的值比没有更危险。

顺带:其余 7 条 status_version 恒为 0 的事件不是待办

每一条的原因已逐条写进事件目录

Webhook 指南。对它们请继续按「到达时间 + 回查确认」处理。

沙盒的上游故障注入真的生效了 不需要动手

POST /v1/sandbox/upstream-behavior 此前只把值写进去、四家上游客户端

一个都不读它(2026-08-12 那条里登记过)。现在注入会真的替换掉该上游

动钱那一跳的响应,我方随即照生产上逐字相同的逻辑处置它。

于是这三条平时无法按需触发的路径可以在沙盒里跑了:

timeout / unknown(→ 结果不明,钱继续锁着)、

reject(→ 判死并释放冻结)、

unknown_status(→ 挂起并告警,不 default 成「处理中」)。

不需要你动手,但强烈建议加一步联调:注一次 timeout,把你的

「结果不明」分支真的跑一遍 —— 那是整套接入里最容易只写不测的分支,

而它写错的后果是既退款又付款。详见 沙盒

⚠ 同一家上游的只读调用(报价、解码、查询)不受注入影响,照常打真实上游;

这两个端点在 live 上仍然是 404

业务拒绝不再以 500 返回 需要你动手

「余额不足」「报价过期」「该方向未启用」「地址校验和不对」这类合法的业务拒绝

此前走对外码目录的缺省分支,以 500 api_error 返回。现在逐条有明确的 4xx code

需要你动手:如果你为此写过「对 500 也重试」的绕行代码,请拆掉并改成按 code 分支。

新增对外码 amount_out_of_range(金额超出产品区间)——

它与 limit_exceeded 的处置相反:那条是额度用完了要等,这条改个数就能过。

同时删掉了目录里 21 个零发射点的死键,并加了守卫

(内部码没登记、或登记了却没人发,提交期就红)。

四个一调用就 500 的端点修好了 不需要动手

GET /v1/cards/{id} · GET /v1/cards/{id}/transactions ·

GET /v1/earn/products/{id} · POST /v1/cards/{id}/replacements

卡消费流水新增 direction 出参 —— amount 是绝对值,

只看金额的话一笔退款与一笔消费长得一模一样。

汇款详情不再回显内部状态,金额格式与列表统一 需要你动手

GET /v1/remittances/{id} 此前可能返回 pending_merchant_funds

(列表与下单口都折叠成 pending),且 source_amount 是未插小数点的

定点整数串 —— 同一笔单在两个端点上差 10^ledger_scale 倍。

需要你动手:如果你为「详情与列表金额对不上」写过换算,请拆掉。

现在两边都是十进制串并随行下发 ledger_scale

GET /v1/merchant/custody 随行下发 ledger_scale 不需要动手

对账用的两个数是定点整数串,此前不下发位数,而同一条线的

/v1/merchant/statements 一直下发 —— 商户在一个端点上能正确定标、

在另一个上只能猜。null 表示该资产已从目录下架(对账表会留历史行)。

89 个端点补齐参数、请求体、响应与示例 不需要动手

此前 spec 里只有「方法 + 路径 + 一句话 + scope」,没有任何字段声明。

现在每个端点一页,含参数表、请求体字段、响应示例、三种语言的调用样例。

接口行为没有变化,变的只是文档。

错误码目录公开,共 42 个对外码 需要你动手

新增 /errors 页,逐条写明含义与你该怎么处置(该重试的、

不能重试的、需要人介入的)。

需要你动手:如果你的实现里有「按 HTTP 状态码分支」的重试逻辑,

请改成code 分支。几个反直觉的:service_unavailable

limit_exceededasset_not_allowedstate_invalid 都是 400 不是 5xx

事件目录公开,共 20 条 需要你动手

新增 /events 页,含事件体示例与投递语义。

需要你动手:目录里逐条标注了 data.id 的真实形态与

status_version 是否可用 —— 有 9 条事件的 status_version 恒为 0

如果你写了「version 不大于当前值就跳过」的合并器,这 9 条只有第一条会生效。

在我方修好之前,请对这几条改用「按到达时间 + 回查确认」。

分页信封统一为 { data, next_cursor, has_more } 不需要动手

静态清单端点(如 GET /v1/transfers/recipient-types)也返回同一个信封,

你的通用翻页器不需要为它们开特例。

⚠ 一处例外尚未收口:GET /v1/balances 仍返回 { balances: [...] }

端点页上已标注,修好后会在这里登记。

业务端点开始限流 需要你动手

按商户 × 桶计:入金上报 60/分钟、建会员 300/分钟、其余写 120/分钟、

读 1200/分钟。超出返回 429 + Retry-After

需要你动手:把 429 当正常路径处理并按 Retry-After 退避。

收到 429 不代表你被封了。详见 限流

Webhook 投递改为按端点扇出 不需要动手

此前「一个 2xx 就算全成功」:配了三个端点、一个通两个 500 时,

那两个永远不会重试而记录显示已送达。现在一行 = 一个(事件, 端点),

各自退避;新增 no_subscriber 一档(零行看起来像「还没有事件」而不是「坏了」)。

沙盒事件与生产隔离 不需要动手

投递行带环境,订阅端点查询带环境谓词。沙盒端点不再收到生产事件。

⚠ 上游故障注入器当时是空操作(注入之后仍打真实上游)。

已于 2026-08-13 修好(见本页最新那一条),详见 沙盒