Z Zise Developers
POST /v1/withdrawals

提现扣账(available → withdrawing)

Scope withdrawals:write 代会员调用 · 必带 x-on-behalf-of x-idempotency-key 动钱 · 会员 available 减少,同额进 withdrawing(merchant.custody 不动)
这个端点会动钱

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

把会员的钱从 available 挪进 withdrawing此刻钱不可再用

merchant.custody 不动 —— 钱还在你手上,你还欠着会员。

为什么必须先调这一步再上链:会员余额得在我方账本上真的减少

否则同一笔钱能在我方产品上(汇款、兑换、发卡、理财)再花一次。

上链成功后调 POST /v1/withdrawals/{id}/confirm

失败调 .../fail 退回 available。没有第三条路 ——

钱不会自己从 withdrawing 里出来,你不推它就永远停在那里。

⚠⚠ 已知偏差,不要照着它设计产品

这个端点目前直接收请求体里的 to_address:不查地址簿、

不判 24 小时冷静期、不要求强认证。而同一条线的设计纪律写的是

「地址簿是提现主线里唯一的地址来源,主线里没有输入地址的输入框」——

代码与纪律在这一处不一致。

所有者已决定把会员充值提现从商户面撤掉,所以本端点后续可能下线。

在那之前:请你在自己那一侧先调 GET /v1/withdraw-addresses

取会员已备案且 usable=true 的地址,把它填进 to_address

不要把这里当成「可以填任意地址」的接口用

前置条件

  • 资产在平台目录内且已启用
  • 会员该资产的可用余额 ≥ amount
  • 会员未被封禁 / 拉黑 / 冻结
字段类型必填说明
x-on-behalf-of string 必填 给哪个会员扣账
x-idempotency-key string 必填 UUID。这把键是防重复扣账的唯一保护 —— 与入金不同, 这个端点没有 reference 那样的业务流水号, 重发时换了新键就是第二次真实扣账

请求体

字段类型必填说明
asset string 必填 资产代码,自动转大写。不在目录内回 asset_not_allowed
amount string 必填 扣账数量,必须 > 0。字符串定点,位数 = 该资产 ledger_scale;超出位数且尾数非全 0 直接 400。USDT(ledger_scale=6)形如 200.000000
to_address string 必填 收款地址,≤ 200 字符。会原样快照进订单行, 之后查询返回的就是这一份,改不了。 ⚠ 我方在这个端点上不做地址格式校验、不查地址簿、 不判冷静期(见上方「已知偏差」)—— 校验责任在你那一侧。

响应

201已扣账,等你上链
{
  "id": "wdr_9f1c0b2a-4d33-4a51-9f2e-7c1b0a5d6e88",
  "status": "locked",
  "asset": "USDT",
  "amount": "200.000000",
  "ledger_scale": 6,
  "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}
400invalid_request 缺字段 / 金额非法 / 地址超 200 字符 · asset_not_allowed 资产不在目录 · insufficient_balance 会员可用余额不足 · limit_exceeded 撞会员侧限额(limit_scope = member) · request_rejected 平台准入拦下(不下发原因
409idempotency_key_reused · idempotency_in_progress
调用样例
curl -X POST 'https://api.zise.com/v1/withdrawals' \
  -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 '{
    "asset": "USDT",
    "amount": "200.000000",
    "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
  }'
const res = await fetch(
  "https://api.zise.com/v1/withdrawals",
  {
    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({
      "asset": "USDT",
      "amount": "200.000000",
      "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
    }),
  },
);
// 金额一律按字符串读,不要 JSON.parse 成 number
const data = await res.json();
import requests

res = requests.post(
    "https://api.zise.com/v1/withdrawals",
    headers={
        "authorization": "Bearer $TOKEN",
        "x-zise-merchant": "$MERCHANT_ID",
        "x-on-behalf-of": "$MEMBER_ID",
        "x-idempotency-key": "$(uuidgen)",
        "content-type": "application/json"
    },
    json={
        "asset": "USDT",
        "amount": "200.000000",
        "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
    },
)
# 金额用 Decimal(str(...)),不要 float
data = res.json()