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-action 的 deadline 是唯一的倒计时依据。
轮数是有限的
同一单能重新确认的次数有上限,用尽后 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"
}400
invalid_request 请求体不是合法 JSON,或 accept_total 为空。
state_invalid 三种:这单不在 needs_reconfirm
(含并发下已被别人推成终态)、已过 4 小时时效、
accept_total 与我方此刻算出的值不一致
(重新查一次 pending-action 再问用户一遍,别自动重发)。
insufficient_balance 会员该资产可用余额不够补冻。404
not_found 订单不在这个会员名下。500⚠ 当前实现:重新确认轮数用尽落到这里(
api_error),
而不是一个 400。所以别在收到 500 时自动重发 ——
先查 pending-action:can_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()