Z Zise Developers

提现扣账(available → withdrawing)

POST /v1/withdrawals 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

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

── 这条线可以被我方停掉 ──

本端点受你的 withdraw 业务线开关约束(同 GET /v1/merchant/lines

里的那一条)。线没开、被人工停售、或预付余额掉进低水位触发自动停售时,

这里一律回 400 service_unavailable不排队:它是即时成交线,

没有「等你充值之后自动继续」这一档,扣账要么当场成功要么当场失败。

处置:先看 GET /v1/merchant/lineshalted=true 的会随着预付充值

在下一轮巡检自己解除;enabled=false 只能找客户经理。

⚠ 已经 locked 的单不受影响 —— confirm / fail 照常可调,

停售的意思是「别再开新的了」,不是把在途的钉死在 withdrawing 里。

前置条件

  • 资产在平台目录内且已启用
  • 会员该资产的可用余额 ≥ amount
  • 会员未被封禁 / 拉黑 / 冻结
  • 你的 withdraw 业务线已开通、未被停售,且商户资产账户状态正常
字段类型必填说明
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 平台准入拦下(不下发原因) · service_unavailable 你的 withdraw 线没开 / 已停售 / 商户资产账户被处置 —— 原样重试不会变,先看 GET /v1/merchant/lines
409idempotency_key_reused · idempotency_in_progress
请求
curl -X POST 'https://api.zise.com/v1/withdrawals' \
  -H 'x-auth-token: Bearer $TOKEN' \
  -H 'x-on-behalf-of: $MEMBER_ID' \
  -H 'x-idempotency-key: $IDEMPOTENCY_KEY' \
  -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: {
    "x-auth-token": "Bearer $TOKEN",
    "x-on-behalf-of": "$MEMBER_ID",
    "x-idempotency-key": "$IDEMPOTENCY_KEY",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "asset": "USDT",
    "amount": "200.000000",
    "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
  }),
});
// 金额按字符串读,别让它变成 number
const data = await res.json();
import requests

res = requests.post(
    "https://api.zise.com/v1/withdrawals",
    headers={
        "x-auth-token": "Bearer $TOKEN",
        "x-on-behalf-of": "$MEMBER_ID",
        "x-idempotency-key": "$IDEMPOTENCY_KEY",
        "content-type": "application/json",
    },
    json={
      "asset": "USDT",
      "amount": "200.000000",
      "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
    },
)
# 金额用 Decimal(str(...)),不要 float
data = res.json()
req, _ := http.NewRequest("POST", "https://api.zise.com/v1/withdrawals",
    strings.NewReader(`{
  "asset": "USDT",
  "amount": "200.000000",
  "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}`))
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
req.Header.Set("x-idempotency-key", "$IDEMPOTENCY_KEY")
req.Header.Set("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
// 金额字段用 string 接,不要 float64
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.zise.com/v1/withdrawals"))
    .header("x-auth-token", "Bearer $TOKEN")
    .header("x-on-behalf-of", "$MEMBER_ID")
    .header("x-idempotency-key", "$IDEMPOTENCY_KEY")
    .header("content-type", "application/json")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
{
  "asset": "USDT",
  "amount": "200.000000",
  "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}
"""))
    .build();
// 金额字段用 String / BigDecimal,不要 double
$ch = curl_init('https://api.zise.com/v1/withdrawals');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'x-auth-token: Bearer $TOKEN',
    'x-on-behalf-of: $MEMBER_ID',
    'x-idempotency-key: $IDEMPOTENCY_KEY',
    'content-type: application/json',
  ],
  CURLOPT_POSTFIELDS => <<<'JSON'
{
  "asset": "USDT",
  "amount": "200.000000",
  "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}
JSON,
]);
$res = curl_exec($ch);
// 金额用 bcmath / 字符串,不要 floatval
201
{
  "id": "wdr_9f1c0b2a-4d33-4a51-9f2e-7c1b0a5d6e88",
  "status": "locked",
  "asset": "USDT",
  "amount": "200.000000",
  "ledger_scale": 6,
  "to_address": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
}