Z Zise Developers
POST /v1/remittances/{id}/reconfirm

接受涨价并补冻(4 小时时效)

Scope remittances:write 代会员调用 · 必带 x-on-behalf-of x-idempotency-key 动钱 · 补冻差额(extra_locked)进 locked 桶,并同步补冻你的预付备付金
这个端点会动钱

失败处置见下方响应表。超时(504)用同一把幂等键重试——我方可能已经处理完;业务失败要换新键,同键会原样返回那次失败。

分发时算出的成交成本相对下单快照上浮超过了用户设的滑点上限,

我方停下来问而不是默默多扣。这个端点是「用户说:行,我多付」。

成功后订单回到 dispatching,差额已经补冻进 locked

accept_total 必须逐字相等

它是用户在你界面上看到的那个「共计扣除」,必须逐字等于

GET /v1/remittances/{id}/pending-action 此刻返回的 new_total

不等说明期间又跑了一轮分发、价格已经变了 —— 这时候按旧数字扣款

就是扣了一个他没同意的数。所以流程只能是:

**先查 pending-action,把 new_total 显示给用户,用户点确认,

把那个串原样发回来。** 别自己算,别缓存。

4 小时,过期自动退款

进入 needs_reconfirm 那一刻起算(不是下单时间 ——

这单可能在审核里躺了 23 小时才轮到分发,而用户此刻才第一次被告知

要做决定)。过期后由巡检解冻退款,这个端点不解冻

两处都能解会出现「谁先跑谁说了算」的竞态。

pending-actiondeadline 是唯一的倒计时依据。

轮数是有限的

同一单能重新确认的次数有上限,用尽后 can_accept: false

reject_reason: too_many_rounds。这时只剩取消或等它过期。

⚠ 补冻是真的动钱:会员该资产的可用余额要够 extra_locked

(含滑点预留,所以 ≥ extra_charge)。不够时先判后拒,

不会让他撞一个 500。

前置条件

  • 订单状态是 needs_reconfirm 且未过 4 小时时效
  • accept_total 逐字等于 pending-action 此刻的 new_total
  • 会员该资产可用余额 ≥ extra_locked
  • 重新确认轮数未用尽

路径参数

字段类型必填说明
id string 必填 订单号。rmt_ 前缀可带可不带。
字段类型必填说明
x-on-behalf-of string 必填 代哪个会员调用。
x-idempotency-key string 必填 UUID v4。补冻是动钱的,重试沿用同一把。

请求体

字段类型必填说明
accept_total string 必填 用户确认的「共计扣除」。字符串定点,位数 = 该资产 ledger_scale;必须逐字等于 pending-action 的 new_total,我方按字符串比对而不是按数值。USDT 为 6 位:"512.340000"

响应

200已接受新价,订单回到分发
{
  "id": "rmt_9c1f0a7e-3b2d-4f81-9a55-1d2e3f4a5b6c",
  "status": "dispatching",
  "locked_amount": "517.463400",
  "new_total": "512.340000"
}
400invalid_request 请求体不是合法 JSON,或 accept_total 为空。 state_invalid 三种:这单不在 needs_reconfirm (含并发下已被别人推成终态)、已过 4 小时时效、 accept_total 与我方此刻算出的值不一致 (重新查一次 pending-action 再问用户一遍,别自动重发)。 insufficient_balance 会员该资产可用余额不够补冻。
404not_found 订单不在这个会员名下。
500⚠ 当前实现:重新确认轮数用尽落到这里(api_error), 而不是一个 400。所以别在收到 500 时自动重发 —— 先查 pending-actioncan_accept: false + reject_reason: too_many_rounds 就是这一档,处置是取消或等它过期。

触发的事件

调用样例
curl -X POST 'https://api.zise.com/v1/remittances/{id}/reconfirm' \
  -H 'authorization: Bearer $TOKEN' \
  -H 'x-zise-merchant: $MERCHANT_ID' \
  -H 'x-on-behalf-of: $MEMBER_ID' \
  -H 'x-idempotency-key: $(uuidgen)' \
  -H 'content-type: application/json' \
  -d '{
    "accept_total": "512.340000"
  }'
const res = await fetch(
  "https://api.zise.com/v1/remittances/{id}/reconfirm",
  {
    method: "POST",
    headers: {
      "authorization": "Bearer $TOKEN",
      "x-zise-merchant": "MERCHANT_ID",
      "x-on-behalf-of": "MEMBER_ID",
      "x-idempotency-key": "crypto.randomUUID()",
      "content-type": "application/json"
    },
    body: JSON.stringify({
      "accept_total": "512.340000"
    }),
  },
);
// 金额一律按字符串读,不要 JSON.parse 成 number
const data = await res.json();
import requests

res = requests.post(
    "https://api.zise.com/v1/remittances/{id}/reconfirm",
    headers={
        "authorization": "Bearer $TOKEN",
        "x-zise-merchant": "$MERCHANT_ID",
        "x-on-behalf-of": "$MEMBER_ID",
        "x-idempotency-key": "$(uuidgen)",
        "content-type": "application/json"
    },
    json={
        "accept_total": "512.340000"
    },
)
# 金额用 Decimal(str(...)),不要 float
data = res.json()