Z Zise Developers 简体中文

Withdrawals have two stages. Funds leave the available balance on submission; the withdrawal must then be confirmed or failed.

Initiating Withdrawals

You execute the on-chain payout: in the merchant_hosted model, you hold the funds. We debit the ledger, reducing the member's balance in our records.


POST /v1/withdrawals               ← 扣账(钱立刻从可用扣走)
POST /v1/withdrawals/{id}/confirm  ← 你确认链上已出款
POST /v1/withdrawals/{id}/fail     ← 你确认出款失败,钱退回

Why the ledger must be debited before the on-chain payout

The member's balance must actually decrease in our ledger before payout. Otherwise, the same funds could be spent again on remittances, conversions, cards or wealth products after they have already been sent on-chain.


State machine: three states, two possible outcomes


        ┌── confirm ──► settled  (终态)
locked ─┤
        └── fail    ──► failed   (终态,钱退回 available)
StateWhere the funds areWho advances the state
lockedThe member.withdrawing bucketOnly you, by calling confirm or fail
settledPaid out; merchant.custody decreases accordingly— Terminal state
failedReturned to member.available— Terminal state

⚠ There is no third outcome. Funds do not leave withdrawing automatically.

Without your confirmation, they stay there indefinitely. The member cannot see or spend them,

and our operations team cannot release that bucket using the unfreeze operation.

This is intentional: a normal freeze could be undone by any unfreeze endpoint,

even if the funds had already been paid out on-chain.

Duplicate calls and conflicting outcomes

CallCurrent stateResult
confirmlocked200; changes to settled
confirmAlready settled200 + replayed: true, an idempotent replay
confirmAlready failed400 order_not_cancellable
failAlready settled400 order_not_cancellable
EitherOrder missing or owned by another merchant404 not_found; identical response for both cases

⚠ fail does not mean cancel. It means “I have confirmed that no on-chain payout occurred; return the funds.”

Calling it before confirming the outcome may return the balance after the funds have already been paid out.

No automatic process can recover that discrepancy.


Destination address

You provide to_address in the request body.

⚠⚠ Known inconsistency: do not design your product around this gap.

This endpoint currently does not consult the address book, enforce the 24-hour cooling-off period or require step-up authentication.

That differs from the intended withdrawal policy that the address book is the only source of destination addresses.

This endpoint may be withdrawn in the future; the product owner has decided to remove member deposits and withdrawals from the merchant-facing interface.

Until then, call GET /v1/withdraw-addresses first, select a registered address for that member

with usable=true, and use it as to_address.

Do not treat this endpoint as permission to send to arbitrary addresses.

Address book


GET  /v1/withdraw-addresses?asset=USDT
POST /v1/withdraw-addresses     ← 挂强认证 + 24 小时冷静期

Addresses belong to the member, not to you. In this model, you custody funds but do not take over the member's identity or security controls.

FieldKey point
usablefalse until the cooling-off period ends
usable_atWhen the address becomes usable
upstream_valid1: provider confirmed validity; -1: provider did not respond (allowed with an audit record)

⚠ Show addresses that are still in their cooling-off period. Hiding a newly added address makes users think the addition failed,

encouraging them to add it again. Display it disabled, with usable_at.

⚠ This list is not paginated. next_cursor is always null and has_more is always false.

These fields are present only to support a shared pagination component.

⚠ The network filter is case-sensitive and matches exactly. Stored values are uppercase machine-readable codes such as BSC.

The asset parameter, however, is normalized to uppercase. The two parameters follow different rules.


The idempotency key is the only duplicate-debit protection

Unlike deposit reporting, POST /v1/withdrawals with x-idempotency-key has no business transaction reference such as reference.

Retrying with a new key causes another real debit. Use your system's unique identifier for that withdrawal.


This service can be suspended

If the service is disabled, manually suspended or automatically halted because your prepaid balance is below the threshold, POST /v1/withdrawals returns 400 service_unavailable. Requests are not queued: the ledger debit either succeeds immediately or fails immediately.

Check GET /v1/merchant/lines first. A line with halted=true recovers automatically on the next monitoring pass after replenishment. For enabled=false, contact your account manager.

⚠ Orders already in locked are unaffected: confirm / fail remain available.

Suspension prevents new withdrawals; it does not trap existing withdrawals in withdrawing.

Other possible failures

CodeMeaning
asset_not_allowedAsset is absent from the platform catalog or has been disabled
insufficient_balanceMember's available balance is insufficient
limit_exceededA limit was exceeded; limit_scope identifies the level
request_rejectedMember is blocked, blacklisted or frozen

Related endpoints