Skip to content

Request an External Withdrawal ​

External withdrawal is asynchronous. Validate the destination and quote before creating a request, then track the result separately.

Validate the destination address ​

Use an external testnet address for this tutorial. If the address belongs to another OOLIN account, the server may classify the movement as an internal transfer.

bash
export TO_ADDRESS='{valid-testnet-address}'
export WITHDRAW_AMOUNT='1.00'

asset_response="$(
  wallet_request GET "/assets/by-type-network?asset_type_id=$ASSET_TYPE_ID&network_id=$NETWORK_ID"
)"
export ASSET_ID="$(printf '%s' "$asset_response" | jq -r '.data.asset_id')"

validate_body="$(jq -nc --arg address "$TO_ADDRESS" '{address:$address}')"
wallet_request POST "/assets/$ASSET_ID/validate-address" "$validate_body" | jq

Continue only when data.is_valid is true.

Request a quote ​

bash
quote_body="$(jq -nc \
  --argjson account_id "$ACCOUNT_ID" \
  --argjson asset_type_id "$ASSET_TYPE_ID" \
  --arg amount "$WITHDRAW_AMOUNT" \
  --arg to_address "$TO_ADDRESS" \
  --argjson network_id "$NETWORK_ID" \
  '{account_id:$account_id,asset_type_id:$asset_type_id,amount:$amount,to_address:$to_address,network_id:$network_id}')"

wallet_request POST '/withdrawals/quote' "$quote_body" | jq

Require can_withdraw: true and transfer_type: "EXTERNAL". Show the customer the fee, receive amount, and applicable minimum or maximum before confirmation.

The reserved and debited account amount is amount + fee_amount; receive_amount is the recipient amount. A quote neither reserves funds nor guarantees success, so handle errors during creation as well.

Create the withdrawal ​

Generate one globally unique client_request_id and persist it before submission.

bash
export WITHDRAWAL_REQUEST_ID="withdrawal-$(node -e 'process.stdout.write(require("crypto").randomUUID())')"

withdrawal_body="$(jq -nc \
  --argjson account_id "$ACCOUNT_ID" \
  --argjson asset_type_id "$ASSET_TYPE_ID" \
  --arg amount "$WITHDRAW_AMOUNT" \
  --arg to_address "$TO_ADDRESS" \
  --argjson network_id "$NETWORK_ID" \
  --arg client_request_id "$WITHDRAWAL_REQUEST_ID" \
  '{account_id:$account_id,asset_type_id:$asset_type_id,amount:$amount,to_address:$to_address,network_id:$network_id,client_request_id:$client_request_id}')"

withdrawal_response="$(wallet_request POST '/withdrawals' "$withdrawal_body")"
printf '%s\n' "$withdrawal_response" | jq

export WITHDRAWAL_ID="$(printf '%s' "$withdrawal_response" | jq -r '.data.withdrawal_id')"

Confirm request_type: "EXTERNAL". At creation, the withdrawal amount and fee move from available balance into the pending withdrawal balance. This reservation is not on-chain completion.

If the create response is lost, recover the existing result before attempting another request:

bash
wallet_request GET "/withdrawals/client-request/$WITHDRAWAL_REQUEST_ID" | jq

After a successful recovery, store the returned withdrawal_id as WITHDRAWAL_ID and continue status polling. A single WITHDRAWAL_NOT_FOUND does not prove the request was never processed; recover with the original ID according to the idempotency guide.

Next: Track withdrawal status.

OOLIN is a digital asset operations infrastructure product by BPMG.